`]: ../std/boxed/struct.Box.html
-[`Clone`]: ../std/clone/trait.Clone.html
-[`Copy`]: ../std/marker/trait.Copy.html
-[`Deref`]: ../std/ops/trait.Deref.html
-[`DerefMut`]: ../std/ops/trait.DerefMut.html
-[`Drop`]: ../std/ops/trait.Drop.html
-[`Pin`]: ../std/pin/struct.Pin.html
-[`Rc`]: ../std/rc/struct.Rc.html
-[`RefUnwindSafe`]: ../std/panic/trait.RefUnwindSafe.html
-[`Send`]: ../std/marker/trait.Send.html
-[`Sized`]: ../std/marker/trait.Sized.html
-[`std::cell::UnsafeCell`]: ../std/cell/struct.UnsafeCell.html
-[`std::cmp`]: ../std/cmp/index.html
-[`std::marker::PhantomData`]: ../std/marker/struct.PhantomData.html
-[`std::ops`]: ../std/ops/index.html
-[`Termination`]: ../std/process/trait.Termination.html
-[`UnwindSafe`]: ../std/panic/trait.UnwindSafe.html
-[`Sync`]: ../std/marker/trait.Sync.html
-[`Unpin`]: ../std/marker/trait.Unpin.html
+[`Arc`]: std::sync::Arc
+[`Deref`]: std::ops::Deref
+[`DerefMut`]: std::ops::DerefMut
+[`Pin`]: std::pin::Pin
+[`Rc`]: std::rc::Rc
+[`RefUnwindSafe`]: std::panic::RefUnwindSafe
+[`Termination`]: std::process::Termination
+[`UnwindSafe`]: std::panic::UnwindSafe
+[`Unpin`]: std::marker::Unpin
[Arrays]: types/array.md
[associated types]: items/associated-items.md#associated-types
@@ -181,7 +170,7 @@ These implicit `Sized` bounds may be relaxed by using the special `?Sized` bound
[orphan rules]: items/implementations.md#trait-implementation-coherence
[`static` items]: items/static-items.md
[test functions]: attributes/testing.md#the-test-attribute
-[the standard library]: ../std/index.html
+[the standard library]: std
[trait object]: types/trait-object.md
[Tuples]: types/tuple.md
[Type parameters]: types/parameters.md
diff --git a/src/statements-and-expressions.md b/src/statements-and-expressions.md
index fede411..b749696 100644
--- a/src/statements-and-expressions.md
+++ b/src/statements-and-expressions.md
@@ -1,5 +1,7 @@
# Statements and expressions
+r[stmt-expr]
+
Rust is _primarily_ an expression language.
This means that most forms of value-producing or effect-causing evaluation are directed by the uniform syntax category of _expressions_.
Each kind of expression can typically _nest_ within each other kind of expression, and rules for evaluation of expressions involve specifying both the value produced by the expression and the order in which its sub-expressions are themselves evaluated.
diff --git a/src/statements.md b/src/statements.md
index 40f95be..5ee35d9 100644
--- a/src/statements.md
+++ b/src/statements.md
@@ -1,5 +1,8 @@
# Statements
+r[statement]
+
+r[statement.syntax]
> **Syntax**\
> _Statement_ :\
> `;`\
@@ -8,13 +11,16 @@
> | [_ExpressionStatement_]\
> | [_MacroInvocationSemi_]
-
+r[statement.intro]
A *statement* is a component of a [block], which is in turn a component of an outer [expression] or [function].
+r[statement.kind]
Rust has two kinds of statement: [declaration statements](#declaration-statements) and [expression statements](#expression-statements).
## Declaration statements
+r[statement.decl]
+
A *declaration statement* is one that introduces one or more *names* into the enclosing statement block.
The declared names may denote new variables or new [items][item].
@@ -22,12 +28,20 @@ The two kinds of declaration statements are item declarations and `let` statemen
### Item declarations
+r[statement.item]
+
+r[statement.item.intro]
An *item declaration statement* has a syntactic form identical to an [item declaration][item] within a [module].
+
+r[statement.item.scope]
Declaring an item within a statement block restricts its [scope] to the block containing the statement.
The item is not given a [canonical path] nor are any sub-items it may declare.
+
+r[statement.item.associated-scope]
The exception to this is that associated items defined by [implementations] are still accessible in outer scopes as long as the item and, if applicable, trait are accessible.
It is otherwise identical in meaning to declaring the item inside a module.
+r[statement.item.outer-generics]
There is no implicit capture of the containing function's generic parameters, parameters, and local variables.
For example, `inner` may not access `outer_var`.
@@ -43,6 +57,9 @@ fn outer() {
### `let` statements
+r[statement.let]
+
+r[statement.let.syntax]
> **Syntax**\
> _LetStatement_ :\
> [_OuterAttribute_]\* `let` [_PatternNoTopAlt_]
@@ -52,13 +69,21 @@ fn outer() {
> † When an `else` block is specified, the
> _Expression_ must not be a [_LazyBooleanExpression_], or end with a `}`.
+r[statement.let.intro]
A *`let` statement* introduces a new set of [variables], given by a [pattern].
The pattern is followed optionally by a type annotation and then either ends, or is followed by an initializer expression plus an optional `else` block.
+
+r[statement.let.inference]
When no type annotation is given, the compiler will infer the type, or signal an error if insufficient type information is available for definite inference.
+
+r[statement.let.scope]
Any variables introduced by a variable declaration are visible from the point of declaration until the end of the enclosing block scope, except when they are shadowed by another variable declaration.
+r[statement.let.constraint]
If an `else` block is not present, the pattern must be irrefutable.
If an `else` block is present, the pattern may be refutable.
+
+r[statement.let.behavior]
If the pattern does not match (this requires it to be refutable), the `else` block is executed.
The `else` block must always diverge (evaluate to the [never type]).
@@ -75,17 +100,24 @@ let [u, v] = [v[0], v[1]] else { // This pattern is irrefutable, so the compiler
## Expression statements
+r[statement.expr]
+
+r[statement.expr.syntax]
> **Syntax**\
> _ExpressionStatement_ :\
> [_ExpressionWithoutBlock_][expression] `;`\
> | [_ExpressionWithBlock_][expression] `;`?
+r[statement.expr.intro]
An *expression statement* is one that evaluates an [expression] and ignores its result.
As a rule, an expression statement's purpose is to trigger the effects of evaluating its expression.
+r[statement.expr.restriction-semicolon]
An expression that consists of only a [block expression][block] or control flow expression, if used in a context where a statement is permitted, can omit the trailing semicolon.
This can cause an ambiguity between it being parsed as a standalone statement and as a part of another expression;
in this case, it is parsed as a statement.
+
+r[statement.expr.constraint-block]
The type of [_ExpressionWithBlock_][expression] expressions when used as statements must be the unit type.
```rust
@@ -118,6 +150,8 @@ if true {
## Attributes on Statements
+r[statement.attribute]
+
Statements accept [outer attributes].
The attributes that have meaning on a statement are [`cfg`], and [the lint check attributes].
diff --git a/src/subtyping.md b/src/subtyping.md
index b31e25d..38fb127 100644
--- a/src/subtyping.md
+++ b/src/subtyping.md
@@ -1,7 +1,13 @@
# Subtyping and Variance
+r[subtype]
+
+r[subtype.intro]
Subtyping is implicit and can occur at any stage in type checking or
-inference. Subtyping is restricted to two cases:
+inference.
+
+r[subtype.kinds]
+Subtyping is restricted to two cases:
variance with respect to lifetimes and between types with higher ranked
lifetimes. If we were to erase lifetimes from types, then the only subtyping
would be due to type equality.
@@ -19,6 +25,7 @@ fn bar<'a>() {
Since `'static` outlives the lifetime parameter `'a`, `&'static str` is a
subtype of `&'a str`.
+r[subtype.higher-ranked]
[Higher-ranked] [function pointers] and [trait objects] have another
subtype relation. They are subtypes of types that are given by substitutions of
the higher-ranked lifetimes. Some examples:
@@ -39,17 +46,26 @@ let supertype: &for<'c> fn(&'c i32, &'c i32) = subtype;
## Variance
+r[subtyping.variance]
+
+r[subtyping.variance.intro]
Variance is a property that generic types have with respect to their arguments.
A generic type's *variance* in a parameter is how the subtyping of the
parameter affects the subtyping of the type.
+r[subtyping.variance.covariant]
* `F` is *covariant* over `T` if `T` being a subtype of `U` implies that
`F` is a subtype of `F` (subtyping "passes through")
+
+r[subtyping.variance.contravariant]
* `F` is *contravariant* over `T` if `T` being a subtype of `U` implies that
`F` is a subtype of `F`
+
+r[subtyping.variance.invariant]
* `F` is *invariant* over `T` otherwise (no subtyping relation can be
derived)
+r[subtyping.variance.builtin-types]
Variance of types is automatically determined as follows
| Type | Variance in `'a` | Variance in `T` |
@@ -65,6 +81,7 @@ Variance of types is automatically determined as follows
| `std::marker::PhantomData` | | covariant |
| `dyn Trait + 'a` | covariant | invariant |
+r[subtyping.variance.user-composite-types]
The variance of other `struct`, `enum`, and `union` types is decided by
looking at the variance of the types of their fields. If the parameter is used
in positions with different variances then the parameter is invariant. For
@@ -85,6 +102,7 @@ struct Variance<'a, 'b, 'c, T, U: 'a> {
}
```
+r[subtyping.variance.builtin-composite-types]
When used outside of an `struct`, `enum`, or `union`, the variance for parameters is checked at each location separately.
```rust
diff --git a/src/test-summary.md b/src/test-summary.md
new file mode 100644
index 0000000..e4e3e74
--- /dev/null
+++ b/src/test-summary.md
@@ -0,0 +1,5 @@
+# Test summary
+
+The following is a summary of the total tests that are linked to individual rule identifiers within the reference.
+
+{{summary-table}}
diff --git a/src/tokens.md b/src/tokens.md
index b14fd33..46174b3 100644
--- a/src/tokens.md
+++ b/src/tokens.md
@@ -1,5 +1,8 @@
# Tokens
+r[lex.token]
+
+r[lex.token.intro]
Tokens are primitive productions in the grammar defined by regular
(non-recursive) languages. Rust source input can be broken down
into the following kinds of tokens:
@@ -18,6 +21,7 @@ table production] form, and appear in `monospace` font.
## Literals
+r[lex.token.literal]
Literals are tokens used in [literal expressions].
### Examples
@@ -88,13 +92,17 @@ Literals are tokens used in [literal expressions].
#### Suffixes
-A suffix is a sequence of characters following the primary part of a literal (without intervening whitespace), of the same form as a non-raw identifier or keyword.
+r[lex.token.literal.suffix]
+r[lex.token.literal.literal.suffix.intro]
+A suffix is a sequence of characters following the primary part of a literal (without intervening whitespace), of the same form as a non-raw identifier or keyword.
+r[lex.token.literal.suffix.syntax]
> **Lexer**\
> SUFFIX : IDENTIFIER_OR_KEYWORD\
> SUFFIX_NO_E : SUFFIX _not beginning with `e` or `E`_
+r[lex.token.literal.suffix.validity]
Any kind of literal (string, integer, etc) with any suffix is valid as a token.
A literal token with any suffix can be passed to a macro without producing an error.
@@ -109,6 +117,7 @@ blackhole!("string"suffix); // OK
blackhole_lit!(1suffix); // OK
```
+r[lex.token.literal.suffix.parse]
However, suffixes on literal tokens which are interpreted as literal expressions or patterns are restricted.
Any suffixes are rejected on non-numeric literal tokens,
and numeric literal tokens are accepted only with suffixes from the list below.
@@ -121,6 +130,9 @@ and numeric literal tokens are accepted only with suffixes from the list below.
#### Character literals
+r[lex.token.literal.char]
+
+r[lex.token.literal.char.syntax]
> **Lexer**\
> CHAR_LITERAL :\
> `'` ( ~\[`'` `\` \\n \\r \\t] | QUOTE_ESCAPE | ASCII_ESCAPE | UNICODE_ESCAPE ) `'` SUFFIX?
@@ -135,12 +147,16 @@ and numeric literal tokens are accepted only with suffixes from the list below.
> UNICODE_ESCAPE :\
> `\u{` ( HEX_DIGIT `_`\* )1..6 `}`
+r[lex.token.literal.char.intro]
A _character literal_ is a single Unicode character enclosed within two
`U+0027` (single-quote) characters, with the exception of `U+0027` itself,
which must be _escaped_ by a preceding `U+005C` character (`\`).
#### String literals
+r[lex.token.literal.str]
+
+r[lex.token.literal.str.syntax]
> **Lexer**\
> STRING_LITERAL :\
> `"` (\
@@ -154,10 +170,12 @@ which must be _escaped_ by a preceding `U+005C` character (`\`).
> STRING_CONTINUE :\
> `\` _followed by_ \\n
+r[lex.token.literal.str.intro]
A _string literal_ is a sequence of any Unicode characters enclosed within two
`U+0022` (double-quote) characters, with the exception of `U+0022` itself,
which must be _escaped_ by a preceding `U+005C` character (`\`).
+r[lex.token.literal.str.linefeed]
Line-breaks, represented by the character `U+000A` (LF), are allowed in string literals.
When an unescaped `U+005C` character (`\`) occurs immediately before a line break, the line break does not appear in the string represented by the token.
See [String continuation escapes] for details.
@@ -165,28 +183,43 @@ The character `U+000D` (CR) may not appear in a string literal other than as par
#### Character escapes
+r[lex.token.literal.char-escape]
+
+r[lex.token.literal.char-escape.intro]
Some additional _escapes_ are available in either character or non-raw string
literals. An escape starts with a `U+005C` (`\`) and continues with one of the
following forms:
+r[lex.token.literal.char-escape.ascii]
* A _7-bit code point escape_ starts with `U+0078` (`x`) and is
followed by exactly two _hex digits_ with value up to `0x7F`. It denotes the
ASCII character with value equal to the provided hex value. Higher values are
not permitted because it is ambiguous whether they mean Unicode code points or
byte values.
+
+r[lex.token.literal.char-escape.unicode]
* A _24-bit code point escape_ starts with `U+0075` (`u`) and is followed
by up to six _hex digits_ surrounded by braces `U+007B` (`{`) and `U+007D`
(`}`). It denotes the Unicode code point equal to the provided hex value.
+
+r[lex.token.literal.char-escape.whitespace]
* A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072`
(`r`), or `U+0074` (`t`), denoting the Unicode values `U+000A` (LF),
`U+000D` (CR) or `U+0009` (HT) respectively.
+
+r[lex.token.literal.char-escape.null]
* The _null escape_ is the character `U+0030` (`0`) and denotes the Unicode
value `U+0000` (NUL).
+
+r[lex.token.literal.char-escape.slash]
* The _backslash escape_ is the character `U+005C` (`\`) which must be
escaped in order to denote itself.
#### Raw string literals
+r[lex.token.literal.str-raw]
+
+r[lex.token.literal.str-raw.syntax]
> **Lexer**\
> RAW_STRING_LITERAL :\
> `r` RAW_STRING_CONTENT SUFFIX?
@@ -195,13 +228,16 @@ following forms:
> `"` ( ~ _IsolatedCR_ )* (non-greedy) `"`\
> | `#` RAW_STRING_CONTENT `#`
+r[lex.token.literal.str-raw.intro]
Raw string literals do not process any escapes. They start with the character
`U+0072` (`r`), followed by fewer than 256 of the character `U+0023` (`#`) and a
`U+0022` (double-quote) character.
+r[lex.token.literal.str-raw.body]
The _raw string body_ can contain any sequence of Unicode characters other than `U+000D` (CR).
It is terminated only by another `U+0022` (double-quote) character, followed by the same number of `U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote) character.
+r[lex.token.literal.str-raw.content]
All Unicode characters contained in the raw string body represent themselves,
the characters `U+0022` (double-quote) (except when followed by at least as
many `U+0023` (`#`) characters as were used to start the raw string literal) or
@@ -234,6 +270,9 @@ r##"foo #"# bar"##; // foo #"# bar
#### Byte literals
+r[lex.token.byte]
+
+r[lex.token.byte.syntax]
> **Lexer**\
> BYTE_LITERAL :\
> `b'` ( ASCII_FOR_CHAR | BYTE_ESCAPE ) `'` SUFFIX?
@@ -245,6 +284,7 @@ r##"foo #"# bar"##; // foo #"# bar
> `\x` HEX_DIGIT HEX_DIGIT\
> | `\n` | `\r` | `\t` | `\\` | `\0` | `\'` | `\"`
+r[lex.token.byte.intro]
A _byte literal_ is a single ASCII character (in the `U+0000` to `U+007F`
range) or a single _escape_ preceded by the characters `U+0062` (`b`) and
`U+0027` (single-quote), and followed by the character `U+0027`. If the character
@@ -254,6 +294,9 @@ _number literal_.
#### Byte string literals
+r[lex.token.str-byte]
+
+r[lex.token.str-byte.syntax]
> **Lexer**\
> BYTE_STRING_LITERAL :\
> `b"` ( ASCII_FOR_STRING | BYTE_ESCAPE | STRING_CONTINUE )\* `"` SUFFIX?
@@ -261,6 +304,7 @@ _number literal_.
> ASCII_FOR_STRING :\
> _any ASCII (i.e 0x00 to 0x7F), except_ `"`, `\` _and IsolatedCR_
+r[lex.token.str-byte.intro]
A non-raw _byte string literal_ is a sequence of ASCII characters and _escapes_,
preceded by the characters `U+0062` (`b`) and `U+0022` (double-quote), and
followed by the character `U+0022`. If the character `U+0022` is present within
@@ -268,28 +312,40 @@ the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character.
Alternatively, a byte string literal can be a _raw byte string literal_, defined
below.
+r[lex.token.str-byte.linefeed]
Line-breaks, represented by the character `U+000A` (LF), are allowed in byte string literals.
When an unescaped `U+005C` character (`\`) occurs immediately before a line break, the line break does not appear in the string represented by the token.
See [String continuation escapes] for details.
The character `U+000D` (CR) may not appear in a byte string literal other than as part of such a string continuation escape.
+r[lex.token.str-byte.escape]
Some additional _escapes_ are available in either byte or non-raw byte string
literals. An escape starts with a `U+005C` (`\`) and continues with one of the
following forms:
+r[lex.token.str-byte.escape-byte]
* A _byte escape_ escape starts with `U+0078` (`x`) and is
followed by exactly two _hex digits_. It denotes the byte
equal to the provided hex value.
+
+r[lex.token.str-byte.escape-whitespace]
* A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072`
(`r`), or `U+0074` (`t`), denoting the bytes values `0x0A` (ASCII LF),
`0x0D` (ASCII CR) or `0x09` (ASCII HT) respectively.
+
+r[lex.token.str-byte.escape-null]
* The _null escape_ is the character `U+0030` (`0`) and denotes the byte
value `0x00` (ASCII NUL).
+
+r[lex.token.str-byte.escape-slash]
* The _backslash escape_ is the character `U+005C` (`\`) which must be
escaped in order to denote its ASCII encoding `0x5C`.
#### Raw byte string literals
+r[lex.token.str-byte-raw]
+
+r[lex.token.str-byte-raw.syntax]
> **Lexer**\
> RAW_BYTE_STRING_LITERAL :\
> `br` RAW_BYTE_STRING_CONTENT SUFFIX?
@@ -301,14 +357,17 @@ following forms:
> ASCII_FOR_RAW :\
> _any ASCII (i.e. 0x00 to 0x7F) except IsolatedCR_
+r[lex.token.str-byte-raw.intro]
Raw byte string literals do not process any escapes. They start with the
character `U+0062` (`b`), followed by `U+0072` (`r`), followed by fewer than 256
of the character `U+0023` (`#`), and a `U+0022` (double-quote) character.
+r[lex.token.str-byte-raw.body]
The _raw string body_ can contain any sequence of ASCII characters other than `U+000D` (CR).
It is terminated only by another `U+0022` (double-quote) character, followed by the same number of `U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote) character.
A raw byte string literal can not contain any non-ASCII byte.
+r[lex.token.literal.str-byte-raw.content]
All characters contained in the raw string body represent their ASCII encoding,
the characters `U+0022` (double-quote) (except when followed by at least as
many `U+0023` (`#`) characters as were used to start the raw string literal) or
@@ -331,6 +390,9 @@ b"\\x52"; br"\x52"; // \x52
#### C string literals
+r[lex.token.str-c]
+
+r[lex.token.str-c.syntax]
> **Lexer**\
> C_STRING_LITERAL :\
> `c"` (\
@@ -340,39 +402,51 @@ b"\\x52"; br"\x52"; // \x52
> | STRING_CONTINUE\
> )\* `"` SUFFIX?
+r[lex.token.str-c.intro]
A _C string literal_ is a sequence of Unicode characters and _escapes_,
preceded by the characters `U+0063` (`c`) and `U+0022` (double-quote), and
followed by the character `U+0022`. If the character `U+0022` is present within
the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character.
Alternatively, a C string literal can be a _raw C string literal_, defined below.
-[CStr]: ../core/ffi/struct.CStr.html
+[CStr]: core::ffi::CStr
+r[lex.token.str-c.null]
C strings are implicitly terminated by byte `0x00`, so the C string literal
`c""` is equivalent to manually constructing a `&CStr` from the byte string
literal `b"\x00"`. Other than the implicit terminator, byte `0x00` is not
permitted within a C string.
+r[lex.token.str-c.linefeed]
Line-breaks, represented by the character `U+000A` (LF), are allowed in C string literals.
When an unescaped `U+005C` character (`\`) occurs immediately before a line break, the line break does not appear in the string represented by the token.
See [String continuation escapes] for details.
The character `U+000D` (CR) may not appear in a C string literal other than as part of such a string continuation escape.
+r[lex.token.str-c.escape]
Some additional _escapes_ are available in non-raw C string literals. An escape
starts with a `U+005C` (`\`) and continues with one of the following forms:
+r[lex.token.str-c.escape-byte]
* A _byte escape_ escape starts with `U+0078` (`x`) and is followed by exactly
two _hex digits_. It denotes the byte equal to the provided hex value.
+
+r[lex.token.str-c.escape-unicode]
* A _24-bit code point escape_ starts with `U+0075` (`u`) and is followed
by up to six _hex digits_ surrounded by braces `U+007B` (`{`) and `U+007D`
(`}`). It denotes the Unicode code point equal to the provided hex value,
encoded as UTF-8.
+
+r[lex.token.str-c.escape-whitespace]
* A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072`
(`r`), or `U+0074` (`t`), denoting the bytes values `0x0A` (ASCII LF),
`0x0D` (ASCII CR) or `0x09` (ASCII HT) respectively.
+
+r[lex.token.str-c.escape-slash]
* The _backslash escape_ is the character `U+005C` (`\`) which must be
escaped in order to denote its ASCII encoding `0x5C`.
+r[lex.token.str-c.char-unicode]
A C string represents bytes with no defined encoding, but a C string literal
may contain Unicode characters above `U+007F`. Such characters will be replaced
with the bytes of that character's UTF-8 representation.
@@ -385,11 +459,15 @@ c"\u{00E6}";
c"\xC3\xA6";
```
-> **Edition Differences**: C string literals are accepted in the 2021 edition or
+r[lex.token.str-c.edition2021]
+> **Edition differences**: C string literals are accepted in the 2021 edition or
> later. In earlier additions the token `c""` is lexed as `c ""`.
#### Raw C string literals
+r[lex.token.str-c-raw]
+
+r[lex.token.str-c-raw.syntax]
> **Lexer**\
> RAW_C_STRING_LITERAL :\
> `cr` RAW_C_STRING_CONTENT SUFFIX?
@@ -398,19 +476,23 @@ c"\xC3\xA6";
> `"` ( ~ _IsolatedCR_ _NUL_ )* (non-greedy) `"`\
> | `#` RAW_C_STRING_CONTENT `#`
+r[lex.token.str-c-raw.intro]
Raw C string literals do not process any escapes. They start with the
character `U+0063` (`c`), followed by `U+0072` (`r`), followed by fewer than 256
of the character `U+0023` (`#`), and a `U+0022` (double-quote) character.
+r[lex.token.str-c-raw.body]
The _raw C string body_ can contain any sequence of Unicode characters other than `U+0000` (NUL) and `U+000D` (CR).
It is terminated only by another `U+0022` (double-quote) character, followed by the same number of `U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote) character.
+r[lex.token.str-c-raw.content]
All characters contained in the raw C string body represent themselves in UTF-8
encoding. The characters `U+0022` (double-quote) (except when followed by at
least as many `U+0023` (`#`) characters as were used to start the raw C string
literal) or `U+005C` (`\`) do not have any special meaning.
-> **Edition Differences**: Raw C string literals are accepted in the 2021
+r[lex.token.str-c-raw.edition2021]
+> **Edition differences**: Raw C string literals are accepted in the 2021
> edition or later. In earlier additions the token `cr""` is lexed as `cr ""`,
> and `cr#""#` is lexed as `cr #""#` (which is non-grammatical).
@@ -429,11 +511,16 @@ c"\\x52"; cr"\x52"; // \x52
### Number literals
+r[lex.token.literal.num]
+
A _number literal_ is either an _integer literal_ or a _floating-point
literal_. The grammar for recognizing the two kinds of literals is mixed.
#### Integer literals
+r[lex.token.literal.int]
+
+r[lex.token.literal.int.syntax]
> **Lexer**\
> INTEGER_LITERAL :\
> ( DEC_LITERAL | BIN_LITERAL | OCT_LITERAL | HEX_LITERAL )
@@ -459,20 +546,29 @@ literal_. The grammar for recognizing the two kinds of literals is mixed.
>
> HEX_DIGIT : \[`0`-`9` `a`-`f` `A`-`F`]
+r[lex.token.literal.int.kind]
An _integer literal_ has one of four forms:
+r[lex.token.literal.int.kind-dec]
* A _decimal literal_ starts with a *decimal digit* and continues with any
mixture of *decimal digits* and _underscores_.
+
+r[lex.token.literal.int.kind-hex]
* A _hex literal_ starts with the character sequence `U+0030` `U+0078`
(`0x`) and continues as any mixture (with at least one digit) of hex digits
and underscores.
+
+r[lex.token.literal.int.kind-oct]
* An _octal literal_ starts with the character sequence `U+0030` `U+006F`
(`0o`) and continues as any mixture (with at least one digit) of octal digits
and underscores.
+
+r[lex.token.literal.int.kind-bin]
* A _binary literal_ starts with the character sequence `U+0030` `U+0062`
(`0b`) and continues as any mixture (with at least one digit) of binary digits
and underscores.
+r[lex.token.literal.int.restriction]
Like any literal, an integer literal may be followed (immediately, without any spaces) by a suffix as described above.
The suffix may not begin with `e` or `E`, as that would be interpreted as the exponent of a floating-point literal.
See [Integer literal expressions] for the effect of these suffixes.
@@ -525,13 +621,18 @@ Examples of integer literals which are not accepted as literal expressions:
#### Tuple index
+r[lex.token.literal.int.tuple-field]
+
+r[lex.token.literal.int.tuple-field.syntax]
> **Lexer**\
> TUPLE_INDEX: \
> INTEGER_LITERAL
+r[lex.token.literal.int.tuple-field.intro]
A tuple index is used to refer to the fields of [tuples], [tuple structs], and
[tuple variants].
+r[lex.token.literal.int.tuple-field.eq]
Tuple indices are compared with the literal token directly. Tuple indices
start with `0` and each successive index increments the value by `1` as a
decimal value. Thus, only decimal values will match, and the value must not
@@ -551,6 +652,9 @@ let horse = example.0b10; // ERROR no field named `0b10`
#### Floating-point literals
+r[lex.token.literal.float]
+
+r[lex.token.literal.float.syntax]
> **Lexer**\
> FLOAT_LITERAL :\
> DEC_LITERAL `.`
@@ -563,12 +667,14 @@ let horse = example.0b10; // ERROR no field named `0b10`
> (DEC_DIGIT|`_`)\* DEC_DIGIT (DEC_DIGIT|`_`)\*
>
+r[lex.token.literal.float.form]
A _floating-point literal_ has one of two forms:
* A _decimal literal_ followed by a period character `U+002E` (`.`). This is
optionally followed by another decimal literal, with an optional _exponent_.
* A single _decimal literal_ followed by an _exponent_.
+r[lex.token.literal.float.suffix]
Like integer literals, a floating-point literal may be followed by a
suffix, so long as the pre-suffix part does not end with `U+002E` (`.`).
The suffix may not begin with `e` or `E` if the literal does not include an exponent.
@@ -585,7 +691,7 @@ let x: f64 = 2.;
```
This last example is different because it is not possible to use the suffix
-syntax with a floating point literal ending in a period. `2.f64` would attempt
+syntax with a floating point literal end.token.ing in a period. `2.f64` would attempt
to call a method named `f64` on `2`.
Note that `-1.0`, for example, is analyzed as two tokens: `-` followed by `1.0`.
@@ -604,6 +710,8 @@ Examples of floating-point literals which are not accepted as literal expression
#### Reserved forms similar to number literals
+r[lex.token.literal.reserved]
+
> **Lexer**\
> RESERVED_NUMBER :\
> BIN_LITERAL \[`2`-`9`​]\
@@ -616,17 +724,23 @@ Examples of floating-point literals which are not accepted as literal expression
> | `0x` `_`\* _end of input or not HEX_DIGIT_\
> | DEC_LITERAL ( . DEC_LITERAL)? (`e`|`E`) (`+`|`-`)? _end of input or not DEC_DIGIT_
+r[lex.token.literal.reserved.intro]
The following lexical forms similar to number literals are _reserved forms_.
Due to the possible ambiguity these raise, they are rejected by the tokenizer instead of being interpreted as separate tokens.
+r[lex.token.literal.reserved.out-of-range]
* An unsuffixed binary or octal literal followed, without intervening whitespace, by a decimal digit out of the range for its radix.
+r[lex.token.literal.reserved.period]
* An unsuffixed binary, octal, or hexadecimal literal followed, without intervening whitespace, by a period character (with the same restrictions on what follows the period as for floating-point literals).
+r[lex.token.literal.reserved.exp]
* An unsuffixed binary or octal literal followed, without intervening whitespace, by the character `e` or `E`.
+r[lex.token.literal.reserved.empty-with-radix]
* Input which begins with one of the radix prefixes but is not a valid binary, octal, or hexadecimal literal (because it contains no digits).
+r[lex.token.literal.reserved.empty-exp]
* Input which has the form of a floating-point literal with no digits in the exponent.
Examples of reserved forms:
@@ -646,6 +760,9 @@ Examples of reserved forms:
## Lifetimes and loop labels
+r[lex.token.life]
+
+r[lex.token.life.syntax]
> **Lexer**\
> LIFETIME_TOKEN :\
> `'` [IDENTIFIER_OR_KEYWORD][identifier]
@@ -655,16 +772,18 @@ Examples of reserved forms:
>
> LIFETIME_OR_LABEL :\
> `'` [NON_KEYWORD_IDENTIFIER][identifier]
-> _(not immediately followed by `'`)_\
-> | `'_`
> _(not immediately followed by `'`)_
+r[lex.token.life.intro]
Lifetime parameters and [loop labels] use LIFETIME_OR_LABEL tokens. Any
LIFETIME_TOKEN will be accepted by the lexer, and for example, can be used in
macros.
## Punctuation
+r[lex.token.punct]
+
+r[lex.token.punct.intro]
Punctuation symbol tokens are listed here for completeness. Their individual
usages and meanings are defined in the linked pages.
@@ -720,6 +839,8 @@ usages and meanings are defined in the linked pages.
## Delimiters
+r[lex.token.delim]
+
Bracket punctuation is used in various parts of the grammar. An open bracket
must always be paired with a close bracket. Brackets and the tokens within
them are referred to as "token trees" in [macros]. The three types of brackets are:
@@ -732,20 +853,28 @@ them are referred to as "token trees" in [macros]. The three types of brackets
## Reserved prefixes
+r[lex.token.reserved-prefix]
+
+r[lex.token.reserved-prefix.syntax]
> **Lexer 2021+**\
> RESERVED_TOKEN_DOUBLE_QUOTE : ( IDENTIFIER_OR_KEYWORD _Except `b` or `c` or `r` or `br` or `cr`_ | `_` ) `"`\
> RESERVED_TOKEN_SINGLE_QUOTE : ( IDENTIFIER_OR_KEYWORD _Except `b`_ | `_` ) `'`\
> RESERVED_TOKEN_POUND : ( IDENTIFIER_OR_KEYWORD _Except `r` or `br` or `cr`_ | `_` ) `#`
+r[lex.token.reserved-prefix.intro]
Some lexical forms known as _reserved prefixes_ are reserved for future use.
+r[lex.token.reserved-prefix.id]
Source input which would otherwise be lexically interpreted as a non-raw identifier (or a keyword or `_`) which is immediately followed by a `#`, `'`, or `"` character (without intervening whitespace) is identified as a reserved prefix.
+r[lex.token.reserved-prefix.raw-token]
Note that raw identifiers, raw string literals, and raw byte string literals may contain a `#` character but are not interpreted as containing a reserved prefix.
+r[lex.token.reserved-prefix.strings]
Similarly the `r`, `b`, `br`, `c`, and `cr` prefixes used in raw string literals, byte literals, byte string literals, raw byte string literals, C string literals, and raw C string literals are not interpreted as reserved prefixes.
-> **Edition Differences**: Starting with the 2021 edition, reserved prefixes are reported as an error by the lexer (in particular, they cannot be passed to macros).
+r[lex.token.reserved-prefix.edition2021]
+> **Edition differences**: Starting with the 2021 edition, reserved prefixes are reported as an error by the lexer (in particular, they cannot be passed to macros).
>
> Before the 2021 edition, reserved prefixes are accepted by the lexer and interpreted as multiple tokens (for example, one token for the identifier or keyword, followed by a `#` token).
>
diff --git a/src/trait-bounds.md b/src/trait-bounds.md
index 019a2f7..2ff8341 100644
--- a/src/trait-bounds.md
+++ b/src/trait-bounds.md
@@ -1,5 +1,8 @@
# Trait and lifetime bounds
+r[bound]
+
+r[bound.syntax]
> **Syntax**\
> _TypeParamBounds_ :\
> _TypeParamBound_ ( `+` _TypeParamBound_ )\* `+`?
@@ -8,17 +11,18 @@
> _Lifetime_ | _TraitBound_ | _UseBound_
>
> _TraitBound_ :\
-> `?`?
-> [_ForLifetimes_](#higher-ranked-trait-bounds)? [_TypePath_]\
-> | `(` `?`?
-> [_ForLifetimes_](#higher-ranked-trait-bounds)? [_TypePath_] `)`
+> ( `?` |
+> [_ForLifetimes_](#higher-ranked-trait-bounds) )? [_TypePath_]\
+> | `(` ( `?` |
+> [_ForLifetimes_](#higher-ranked-trait-bounds) )? [_TypePath_] `)`
>
> _LifetimeBounds_ :\
> ( _Lifetime_ `+` )\* _Lifetime_?
>
> _Lifetime_ :\
> [LIFETIME_OR_LABEL]\
-> | `'static`
+> | `'static`\
+> | `'_`
>
> _UseBound_ :\
> `use` _UseBoundGenericArgs_
@@ -35,6 +39,7 @@
> | [IDENTIFIER][] \
> | `Self`
+r[bound.intro]
[Trait] and lifetime bounds provide a way for [generic items][generic] to
restrict which types and lifetimes are used as their parameters. Bounds can be
provided on any type in a [where clause]. There are also shorter forms for
@@ -48,6 +53,7 @@ certain common cases:
`trait A { type B: Copy; }` is equivalent to
`trait A where Self::B: Copy { type B; }`.
+r[bound.satisfaction]
Bounds on an item must be satisfied when using the item. When type checking and
borrow checking a generic item, the bounds can be used to determine that a
trait is implemented for a type. For example, given `Ty: Trait`
@@ -87,9 +93,11 @@ fn name_figure(
}
```
+r[bound.trivial]
Bounds that don't use the item's parameters or [higher-ranked lifetimes] are checked when the item is defined.
It is an error for such a bound to be false.
+r[bound.special]
[`Copy`], [`Clone`], and [`Sized`] bounds are also checked for certain generic types when using the item, even if the use does not provide a concrete type.
It is an error to have `Copy` or `Clone` as a bound on a mutable reference, [trait object], or [slice].
It is an error to have `Sized` as a bound on a trait object or slice.
@@ -107,16 +115,24 @@ where
struct UsesA<'a, T>(A<'a, T>);
```
+r[bound.trait-object]
Trait and lifetime bounds are also used to name [trait objects].
## `?Sized`
+r[bound.sized]
+
`?` is only used to relax the implicit [`Sized`] trait bound for [type parameters] or [associated types].
`?Sized` may not be used as a bound for other types.
## Lifetime bounds
+r[bound.lifetime]
+
+r[bound.lifetime.intro]
Lifetime bounds can be applied to types or to other lifetimes.
+
+r[bound.lifetime.outlive-lifetime]
The bound `'a: 'b` is usually read as `'a` *outlives* `'b`.
`'a: 'b` means that `'a` lasts at least as long as `'b`, so a reference `&'a ()` is valid whenever `&'b ()` is valid.
@@ -127,14 +143,19 @@ fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) where 'a: 'b {
}
```
+r[bound.lifetime.outlive-type]
`T: 'a` means that all lifetime parameters of `T` outlive `'a`.
For example, if `'a` is an unconstrained lifetime parameter, then `i32: 'static` and `&'static str: 'a` are satisfied, but `Vec<&'a ()>: 'static` is not.
## Higher-ranked trait bounds
+r[bound.higher-ranked]
+
+r[bound.higher-ranked.syntax]
> _ForLifetimes_ :\
> `for` [_GenericParams_]
+r[bound.higher-ranked.intro]
Trait bounds may be *higher ranked* over lifetimes. These bounds specify a bound
that is true *for all* lifetimes. For example, a bound such as `for<'a> &'a T:
PartialEq` would require an implementation like
@@ -158,6 +179,7 @@ fn call_on_ref_zero(f: F) where for<'a> F: Fn(&'a i32) {
}
```
+r[bound.higher-ranked.trait]
Higher-ranked lifetimes may also be specified just before the trait: the only
difference is the [scope][hrtb-scopes] of the lifetime parameter, which extends only to the
end of the following trait instead of the whole bound. This function is
@@ -172,15 +194,20 @@ fn call_on_ref_zero(f: F) where F: for<'a> Fn(&'a i32) {
## Implied bounds
+r[bound.implied]
+
+r[bound.implied.intro]
Lifetime bounds required for types to be well-formed are sometimes inferred.
```rust
fn requires_t_outlives_a<'a, T>(x: &'a T) {}
```
+
The type parameter `T` is required to outlive `'a` for the type `&'a T` to be well-formed.
This is inferred because the function signature contains the type `&'a T` which is
only valid if `T: 'a` holds.
+r[bound.implied.context]
Implied bounds are added for all parameters and outputs of functions. Inside of `requires_t_outlives_a`
you can assume `T: 'a` to hold even if you don't explicitly specify this:
@@ -203,6 +230,7 @@ fn not_implied<'a, T>() {
}
```
+r[bound.implied.trait]
Only lifetime bounds are implied, trait bounds still have to be explicitly added.
The following example therefore causes an error:
@@ -213,6 +241,7 @@ struct IsDebug(T);
fn doesnt_specify_t_debug(x: IsDebug) {}
```
+r[bound.implied.def]
Lifetime bounds are also inferred for type definitions and impl blocks for any type:
```rust
@@ -244,6 +273,8 @@ impl<'a, T> Trait<'a, T> for &'a T {}
## Use bounds
+r[bound.use]
+
Certain bounds lists may include a `use<..>` bound to control which generic parameters are captured by the `impl Trait` [abstract return type]. See [precise capturing] for more details.
[IDENTIFIER]: identifiers.html
diff --git a/src/type-coercions.md b/src/type-coercions.md
index 2bdbb53..26e27eb 100644
--- a/src/type-coercions.md
+++ b/src/type-coercions.md
@@ -1,9 +1,13 @@
# Type coercions
+r[coerce]
+
+r[coerce.intro]
**Type coercions** are implicit operations that change the type of a value.
They happen automatically at specific locations and are highly restricted in
what types actually coerce.
+r[cerce.as]
Any conversions allowed by coercion can also be explicitly performed by the
[type cast operator], `as`.
@@ -11,11 +15,15 @@ Coercions are originally defined in [RFC 401] and expanded upon in [RFC 1558].
## Coercion sites
+r[coerce.site]
+
+r[coerce.site.intro]
A coercion can only occur at certain coercion sites in a program; these are
typically places where the desired type is explicit or can be derived by
propagation from explicit types (without type inference). Possible coercion
sites are:
+r[coerce.site.let]
* `let` statements where an explicit type is given.
For example, `&mut 42` is coerced to have type `&i8` in the following:
@@ -24,8 +32,10 @@ sites are:
let _: &i8 = &mut 42;
```
+r[coerce.site.value]
* `static` and `const` item declarations (similar to `let` statements).
+r[coerce.site.argument]
* Arguments for function calls
The value being coerced is the actual parameter, and it is coerced to
@@ -44,6 +54,7 @@ sites are:
For method calls, the receiver (`self` parameter) type is coerced
differently, see the documentation on [method-call expressions] for details.
+r[coerce.site.constructor]
* Instantiations of struct, union, or enum variant fields
For example, `&mut 42` is coerced to have type `&i8` in the following:
@@ -56,6 +67,7 @@ sites are:
}
```
+r[coerce.site.return]
* Function results—either the final line of a block if it is not
semicolon-terminated or any expression in a `return` statement
@@ -68,24 +80,30 @@ sites are:
}
```
+r[coerce.site.subexpr]
If the expression in one of these coercion sites is a coercion-propagating
expression, then the relevant sub-expressions in that expression are also
coercion sites. Propagation recurses from these new coercion sites.
Propagating expressions and their relevant sub-expressions are:
+r[coerce.site.array]
* Array literals, where the array has type `[U; n]`. Each sub-expression in
the array literal is a coercion site for coercion to type `U`.
+r[coerce.site.repeat]
* Array literals with repeating syntax, where the array has type `[U; n]`. The
repeated sub-expression is a coercion site for coercion to type `U`.
+r[coerce.site.tuple]
* Tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`.
Each sub-expression is a coercion site to the respective type, e.g. the
zeroth sub-expression is a coercion site to type `U_0`.
+r[coerce.site.parenthesis]
* Parenthesized sub-expressions (`(e)`): if the expression has type `U`, then
the sub-expression is a coercion site to `U`.
+r[coerce.site.block]
* Blocks: if a block has type `U`, then the last expression in the block (if
it is not semicolon-terminated) is a coercion site to `U`. This includes
blocks which are part of control flow statements, such as `if`/`else`, if
@@ -93,23 +111,33 @@ the block has a known type.
## Coercion types
+r[coerce.types]
+
+r[coerce.types.intro]
Coercion is allowed between the following types:
+r[coerce.types.reflexive]
* `T` to `U` if `T` is a [subtype] of `U` (*reflexive case*)
+r[coerce.types.transitive]
* `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3`
(*transitive case*)
Note that this is not fully supported yet.
+r[coerce.types.mut-reborrow]
* `&mut T` to `&T`
+r[coerce.types.mut-pointer]
* `*mut T` to `*const T`
+r[coerce.types.ref-to-pointer]
* `&T` to `*const T`
+r[coerce.types.mut-to-pointer]
* `&mut T` to `*mut T`
+r[coerce.types.deref]
* `&T` or `&mut T` to `&U` if `T` implements `Deref`. For example:
```rust
@@ -135,8 +163,10 @@ Coercion is allowed between the following types:
}
```
+r[coerce.types.deref-mut]
* `&mut T` to `&mut U` if `T` implements `DerefMut`.
+r[coerce.types.unsize]
* TyCtor(`T`) to TyCtor(`U`), where TyCtor(`T`) is one of
- `&T`
- `&mut T`
@@ -150,37 +180,48 @@ Coercion is allowed between the following types:
structs. In addition, coercions from subtraits to supertraits will be
added. See [RFC 401] for more details.-->
+r[coerce.types.fn]
* Function item types to `fn` pointers
+r[coerce.types.closure]
* Non capturing closures to `fn` pointers
+r[coerce.types.never]
* `!` to any `T`
### Unsized Coercions
+r[coerce.unsize]
+
+r[coerce.unsize.intro]
The following coercions are called `unsized coercions`, since they
relate to converting sized types to unsized types, and are permitted in a few
cases where other coercions are not, as described above. They can still happen
anywhere else a coercion can occur.
+r[coerce.unsize.trait]
Two traits, [`Unsize`] and [`CoerceUnsized`], are used
to assist in this process and expose it for library use. The following
coercions are built-ins and, if `T` can be coerced to `U` with one of them, then
an implementation of `Unsize` for `T` will be provided:
+r[coerce.unsize.slice]
* `[T; n]` to `[T]`.
-* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [object safe].
+r[coerce.unsize.trait-object]
+* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [dyn compatible].
+r[coerce.unsized.composite]
* `Foo<..., T, ...>` to `Foo<..., U, ...>`, when:
* `Foo` is a struct.
* `T` implements `Unsize`.
* The last field of `Foo` has a type involving `T`.
- * If that field has type `Bar`, then `Bar` implements `Unsized>`.
+ * If that field has type `Bar`, then `Bar` implements `Unsize>`.
* T is not part of the type of any other fields.
+r[coerce.unsized.pointer]
Additionally, a type `Foo` can implement `CoerceUnsized>` when `T`
-implements `Unsize` or `CoerceUnsized>`. This allows it to provide a
+implements `Unsize` or `CoerceUnsized>`. This allows it to provide an
unsized coercion to `Foo`.
> Note: While the definition of the unsized coercions and their implementation
@@ -189,6 +230,9 @@ unsized coercion to `Foo`.
## Least upper bound coercions
+r[coerce.least-upper-bound]
+
+r[coerce.least-upper-bound.intro]
In some contexts, the compiler must coerce together multiple types to try and
find the most general type. This is called a "Least Upper Bound" coercion.
LUB coercion is used and only used in the following situations:
@@ -199,15 +243,24 @@ LUB coercion is used and only used in the following situations:
+ To find the type for the return type of a closure with multiple return statements.
+ To check the type for the return type of a function with multiple return statements.
+r[coerce.least-upper-bound.target]
In each such case, there are a set of types `T0..Tn` to be mutually coerced
-to some target type `T_t`, which is unknown to start. Computing the LUB
+to some target type `T_t`, which is unknown to start.
+
+r[coerce.least-upper-bound.computation]
+Computing the LUB
coercion is done iteratively. The target type `T_t` begins as the type `T0`.
For each new type `Ti`, we consider whether
+r[coerce.least-upper-bound.computation-identity]
+ If `Ti` can be coerced to the current target type `T_t`, then no change is made.
+
+r[coerce.least-upper-bound.computation-replace]
+ Otherwise, check whether `T_t` can be coerced to `Ti`; if so, the `T_t` is
changed to `Ti`. (This check is also conditioned on whether all of the source
expressions considered thus far have implicit coercions.)
+
+r[coerce.least-upper-bound.computation-unify]
+ If not, try to compute a mutual supertype of `T_t` and `Ti`, which will become the new target type.
### Examples:
@@ -269,8 +322,8 @@ precisely.
[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
[RFC 1558]: https://github.com/rust-lang/rfcs/blob/master/text/1558-closure-to-fn-coercion.md
[subtype]: subtyping.md
-[object safe]: items/traits.md#object-safety
+[dyn compatible]: items/traits.md#dyn-compatibility
[type cast operator]: expressions/operator-expr.md#type-cast-expressions
-[`Unsize`]: ../std/marker/trait.Unsize.html
-[`CoerceUnsized`]: ../std/ops/trait.CoerceUnsized.html
+[`Unsize`]: std::marker::Unsize
+[`CoerceUnsized`]: std::ops::CoerceUnsized
[method-call expressions]: expressions/method-call-expr.md
diff --git a/src/type-layout.md b/src/type-layout.md
index c53e9d0..5d04d2a 100644
--- a/src/type-layout.md
+++ b/src/type-layout.md
@@ -1,16 +1,26 @@
# Type Layout
+r[layout]
+
+r[layout.intro]
The layout of a type is its size, alignment, and the relative offsets of its
fields. For enums, how the discriminant is laid out and interpreted is also part
of type layout.
+r[layout.guarantees]
Type layout can be changed with each compilation. Instead of trying to document
exactly what is done, we only document what is guaranteed today.
+Note that even types with the same layout can still differ in how they are passed
+across function boundaries. For function call ABI compatibility of types,
+see [here][fn-abi-compatibility].
+
## Size and Alignment
+r[layout.properties]
All values have an alignment and size.
+r[layout.properties.align]
The *alignment* of a value specifies what addresses are valid to store the value
at. A value of alignment `n` must only be stored at an address that is a
multiple of n. For example, a value with an alignment of 2 must be stored at an
@@ -18,6 +28,7 @@ even address, while a value with an alignment of 1 can be stored at any address.
Alignment is measured in bytes, and must be at least 1, and always a power of 2.
The alignment of a value can be checked with the [`align_of_val`] function.
+r[layout.properties.size]
The *size* of a value is the offset in bytes between successive elements in an
array with that item type including alignment padding. The size of a value is
always a multiple of its alignment. Note that some types are zero-sized; 0 is
@@ -25,6 +36,7 @@ considered a multiple of any alignment (for example, on some platforms, the type
`[u16; 0]` has size 0 and alignment 2). The size of a value can be checked with
the [`size_of_val`] function.
+r[layout.properties.sized]
Types where all values have the same size and alignment, and both are known at
compile time, implement the [`Sized`] trait and can be checked with the
[`size_of`] and [`align_of`] functions. Types that are not [`Sized`] are known
@@ -34,6 +46,9 @@ the alignment of the type respectively.
## Primitive Data Layout
+r[layout.primitive]
+
+r[layout.primitive.size]
The size of most primitives is given in this table.
| Type | `size_of::()`|
@@ -49,10 +64,12 @@ The size of most primitives is given in this table.
| `f64` | 8 |
| `char` | 4 |
+r[layout.primitive.size-int]
`usize` and `isize` have a size big enough to contain every address on the
target platform. For example, on a 32 bit target, this is 4 bytes, and on a 64
bit target, this is 8 bytes.
+r[layout.primitive.align]
The alignment of primitives is platform-specific.
In most cases, their alignment is equal to their size, but it may be less.
In particular, `i128` and `u128` are often aligned to 4 or 8 bytes even though
@@ -61,11 +78,16 @@ aligned to 4 bytes, not 8.
## Pointers and References Layout
+r[layout.pointer]
+
+r[layout.pointer.intro]
Pointers and references have the same layout. Mutability of the pointer or
reference does not change the layout.
+r[layout.pointer.thin]
Pointers to sized types have the same size and alignment as `usize`.
+r[layout.pointer.unsized]
Pointers to unsized types are sized. The size and alignment is guaranteed to be
at least equal to the size and alignment of a pointer.
@@ -75,29 +97,42 @@ at least equal to the size and alignment of a pointer.
## Array Layout
+r[layout.array]
+
An array of `[T; N]` has a size of `size_of::() * N` and the same alignment
of `T`. Arrays are laid out so that the zero-based `nth` element of the array
is offset from the start of the array by `n * size_of::()` bytes.
## Slice Layout
+r[layout.slice]
+
Slices have the same layout as the section of the array they slice.
> Note: This is about the raw `[T]` type, not pointers (`&[T]`, `Box<[T]>`,
> etc.) to slices.
## `str` Layout
+
+r[layout.str]
+
String slices are a UTF-8 representation of characters that have the same layout as slices of type `[u8]`.
## Tuple Layout
+r[layout.tuple]
+
+r[layout.tuple.general]
Tuples are laid out according to the [`Rust` representation][`Rust`].
+r[layout.tuple.unit]
The exception to this is the unit tuple (`()`), which is guaranteed as a
zero-sized type to have a size of 0 and an alignment of 1.
## Trait Object Layout
+r[layout.trait-object]
+
Trait objects have the same layout as the value the trait object is of.
> Note: This is about the raw trait object types, not pointers (`&dyn Trait`,
@@ -105,19 +140,27 @@ Trait objects have the same layout as the value the trait object is of.
## Closure Layout
+r[layout.closure]
+
Closures have no layout guarantees.
## Representations
+r[layout.repr]
+
+r[layout.repr.intro]
All user-defined composite types (`struct`s, `enum`s, and `union`s) have a
-*representation* that specifies what the layout is for the type. The possible
-representations for a type are:
+*representation* that specifies what the layout is for the type.
+
+r[layout.repr.kinds]
+The possible representations for a type are:
- [`Rust`] (default)
- [`C`]
- The [primitive representations]
- [`transparent`]
+r[layout.repr.attribute]
The representation of a type can be changed by applying the `repr` attribute
to it. The following example shows a struct with a `C` representation.
@@ -130,6 +173,7 @@ struct ThreeInts {
}
```
+r[layout.repr.align-packed]
The alignment may be raised or lowered with the `align` and `packed` modifiers
respectively. They alter the representation specified in the attribute.
If no representation is specified, the default one is altered.
@@ -157,18 +201,24 @@ struct AlignedStruct {
> the same name have the same representation. For example, `Foo` and
> `Foo` both have the same representation.
+r[layout.repr.inter-field]
The representation of a type can change the padding between fields, but does
not change the layout of the fields themselves. For example, a struct with a
-`C` representation that contains a struct `Inner` with the default
+`C` representation that contains a struct `Inner` with the `Rust`
representation will not change the layout of `Inner`.
-### The `Rust` Representation
+
+### The `Rust` Representation
+
+r[layout.repr.rust]
+r[layout.repr.rust.intro]
The `Rust` representation is the default representation for nominal types
without a `repr` attribute. Using this representation explicitly through a
`repr` attribute is guaranteed to be the same as omitting the attribute
entirely.
+r[layout.repr.rust.layout]
The only data layout guarantees made by this representation are those required
for soundness. They are:
@@ -176,8 +226,12 @@ for soundness. They are:
2. The fields do not overlap.
3. The alignment of the type is at least the maximum alignment of its fields.
+r[layout.repr.rust.alignment]
Formally, the first guarantee means that the offset of any field is divisible by
-that field's alignment. The second guarantee means that the fields can be
+that field's alignment.
+
+r[layout.repr.rust.field-storage]
+The second guarantee means that the fields can be
ordered such that the offset plus the size of any field is less than or equal to
the offset of the next field in the ordering. The ordering does not have to be
the same as the order in which the fields are specified in the declaration of
@@ -187,10 +241,14 @@ Be aware that the second guarantee does not imply that the fields have distinct
addresses: zero-sized types may have the same address as other fields in the
same struct.
+r[layout.repr.rust.unspecified]
There are no other guarantees of data layout made by this representation.
### The `C` Representation
+r[layout.repr.c]
+
+r[layout.repr.c.intro]
The `C` representation is designed for dual purposes. One purpose is for
creating types that are interoperable with the C Language. The second purpose is
to create types that you can soundly perform operations on that rely on data
@@ -199,13 +257,18 @@ layout such as reinterpreting values as a different type.
Because of this dual purpose, it is possible to create types that are not useful
for interfacing with the C programming language.
+r[layout.repr.c.constraint]
This representation can be applied to structs, unions, and enums. The exception
is [zero-variant enums] for which the `C` representation is an error.
#### `#[repr(C)]` Structs
+r[layout.repr.c.struct]
+
+r[layout.repr.c.struct.align]
The alignment of the struct is the alignment of the most-aligned field in it.
+r[layout.repr.c.struct.size-field-offset]
The size and offset of fields is determined by the following algorithm.
Start with a current offset of 0 bytes.
@@ -254,13 +317,8 @@ for field in struct.fields_in_declaration_order() {
struct.size = current_offset + padding_needed_for(current_offset, struct.alignment);
```
-
-
-Warning: This pseudocode uses a naive algorithm that ignores overflow issues for
-the sake of clarity. To perform memory layout computations in actual code, use
-[`Layout`].
-
-
+> [!WARNING]
+> This pseudocode uses a naive algorithm that ignores overflow issues for the sake of clarity. To perform memory layout computations in actual code, use [`Layout`].
> Note: This algorithm can produce zero-sized structs. In C, an empty struct
> declaration like `struct Foo { }` is illegal. However, both gcc and clang
@@ -271,8 +329,13 @@ the sake of clarity. To perform memory layout computations in actual code, use
#### `#[repr(C)]` Unions
+r[layout.repr.c.union]
+
+r[layout.repr.c.union.intro]
A union declared with `#[repr(C)]` will have the same size and alignment as an
equivalent C union declaration in the C language for the target platform.
+
+r[layout.repr.c.union.size-align]
The union will have a size of the maximum size of all of its fields rounded to
its alignment, and an alignment of the maximum alignment of all of its fields.
These maximums may come from different fields.
@@ -301,6 +364,8 @@ assert_eq!(std::mem::align_of::(), 4); // From a
#### `#[repr(C)]` Field-less Enums
+r[layout.repr.c.enum]
+
For [field-less enums], the `C` representation has the size and alignment of
the default `enum` size and alignment for the target platform's C ABI.
@@ -308,24 +373,21 @@ the default `enum` size and alignment for the target platform's C ABI.
> really a "best guess". In particular, this may be incorrect when the C code
> of interest is compiled with certain flags.
-
-
-Warning: There are crucial differences between an `enum` in the C language and
-Rust's [field-less enums] with this representation. An `enum` in C is
-mostly a `typedef` plus some named constants; in other words, an object of an
-`enum` type can hold any integer value. For example, this is often used for
-bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold
-the discriminant values, everything else is [undefined behavior]. Therefore,
-using a field-less enum in FFI to model a C `enum` is often wrong.
-
-
+> [!WARNING]
+> There are crucial differences between an `enum` in the C language and Rust's [field-less enums] with this representation. An `enum` in C is mostly a `typedef` plus some named constants; in other words, an object of an `enum` type can hold any integer value. For example, this is often used for bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold the discriminant values, everything else is [undefined behavior]. Therefore, using a field-less enum in FFI to model a C `enum` is often wrong.
#### `#[repr(C)]` Enums With Fields
+r[layout.repr.c.adt]
+
+r[layout.repr.c.adt.intro]
The representation of a `repr(C)` enum with fields is a `repr(C)` struct with
two fields, also called a "tagged union" in C:
+r[layout.repr.c.adt.tag]
- a `repr(C)` version of the enum with all fields removed ("the tag")
+
+r[layout.repr.c.adt.fields]
- a `repr(C)` union of `repr(C)` structs for the fields of each variant that had
them ("the payload")
@@ -388,10 +450,14 @@ struct MyDFields;
### Primitive representations
+r[layout.repr.primitive]
+
+r[layout.repr.primitive.intro]
The *primitive representations* are the representations with the same names as
the primitive integer types. That is: `u8`, `u16`, `u32`, `u64`, `u128`,
`usize`, `i8`, `i16`, `i32`, `i64`, `i128`, and `isize`.
+r[layout.repr.primitive.constraint]
Primitive representations can only be applied to enumerations and have
different behavior whether the enum has fields or no fields. It is an error
for [zero-variant enums] to have a primitive representation. Combining
@@ -399,6 +465,8 @@ two primitive representations together is an error.
#### Primitive Representation of Field-less Enums
+r[layout.repr.primitive.enum]
+
For [field-less enums], primitive representations set the size and alignment to
be the same as the primitive type of the same name. For example, a field-less
enum with a `u8` representation can only have discriminants between 0 and 255
@@ -406,6 +474,8 @@ inclusive.
#### Primitive Representation of Enums With Fields
+r[layout.repr.primitive.adt]
+
The representation of a primitive representation enum is a `repr(C)` union of
`repr(C)` structs for each variant with a field. The first field of each struct
in the union is the primitive representation version of the enum with all fields
@@ -460,6 +530,8 @@ struct MyVariantD(MyEnumDiscriminant);
#### Combining primitive representations of enums with fields and `#[repr(C)]`
+r[layout.repr.primitive-c]
+
For enums with fields, it is also possible to combine `repr(C)` and a
primitive representation (e.g., `repr(C, u8)`). This modifies the [`repr(C)`] by
changing the representation of the discriminant enum to the chosen primitive
@@ -524,6 +596,9 @@ assert_eq!(std::mem::size_of::(), 4);
### The alignment modifiers
+r[layout.repr.alignment]
+
+r[layout.repr.alignment.intro]
The `align` and `packed` modifiers can be used to respectively raise or lower
the alignment of `struct`s and `union`s. `packed` may also alter the padding
between fields (although it will not alter the padding inside of any field).
@@ -532,28 +607,37 @@ of fields in the layout of a struct or the layout of an enum variant, although
they may be combined with representations (such as `C`) which do provide such
guarantees.
+r[layout.repr.alignment.constraint-alignment]
The alignment is specified as an integer parameter in the form of
`#[repr(align(x))]` or `#[repr(packed(x))]`. The alignment value must be a
power of two from 1 up to 229. For `packed`, if no value is given,
as in `#[repr(packed)]`, then the value is 1.
+r[layout.repr.alignment.align]
For `align`, if the specified alignment is less than the alignment of the type
without the `align` modifier, then the alignment is unaffected.
+r[layout.repr.alignment.packed]
For `packed`, if the specified alignment is greater than the type's alignment
without the `packed` modifier, then the alignment and layout is unaffected.
+
+r[layout.repr.alignment.packed-fields]
The alignments of each field, for the purpose of positioning fields, is the
smaller of the specified alignment and the alignment of the field's type.
+
+r[layout.repr.alignment.packed-padding]
Inter-field padding is guaranteed to be the minimum required in order to
satisfy each field's (possibly altered) alignment (although note that, on its
own, `packed` does not provide any guarantee about field ordering). An
important consequence of these rules is that a type with `#[repr(packed(1))]`
(or `#[repr(packed)]`) will have no inter-field padding.
+r[layout.repr.alignment.constraint-exclusive]
The `align` and `packed` modifiers cannot be applied on the same type and a
`packed` type cannot transitively contain another `align`ed type. `align` and
`packed` may only be applied to the [`Rust`] and [`C`] representations.
+r[layout.repr.alignment.enum]
The `align` modifier can also be applied on an `enum`.
When it is, the effect on the `enum`'s alignment is the same as if the `enum`
was wrapped in a newtype `struct` with the same `align` modifier.
@@ -575,39 +659,44 @@ was wrapped in a newtype `struct` with the same `align` modifier.
> println!("{}", {e.f2});
> // Or if you need a pointer, use the unaligned methods for reading and writing
> // instead of dereferencing the pointer directly.
-> let ptr: *const u16 = std::ptr::addr_of!(e.f2);
+> let ptr: *const u16 = &raw const e.f2;
> let value = unsafe { ptr.read_unaligned() };
-> let mut_ptr: *mut u16 = std::ptr::addr_of_mut!(e.f2);
+> let mut_ptr: *mut u16 = &raw mut e.f2;
> unsafe { mut_ptr.write_unaligned(3) }
> ```
### The `transparent` Representation
+r[layout.repr.transparent]
+
+r[layout.repr.transparent.constraint-field]
The `transparent` representation can only be used on a [`struct`][structs]
or an [`enum`][enumerations] with a single variant that has:
+- any number of fields with size 0 and alignment 1 (e.g. [`PhantomData`]), and
+- at most one other field.
-- a single field with non-zero size, and
-- any number of fields with size 0 and alignment 1 (e.g. [`PhantomData`]).
-
+r[layout.repr.transparent.layout-abi]
Structs and enums with this representation have the same layout and ABI
-as the single non-zero sized field.
+as the only non-size 0 non-alignment 1 field, if present, or unit otherwise.
This is different than the `C` representation because
a struct with the `C` representation will always have the ABI of a `C` `struct`
while, for example, a struct with the `transparent` representation with a
primitive field will have the ABI of the primitive field.
+r[layout.repr.transparent.constraint-exclusive]
Because this representation delegates type layout to another type, it cannot be
used with any other representation.
-[`align_of_val`]: ../std/mem/fn.align_of_val.html
-[`size_of_val`]: ../std/mem/fn.size_of_val.html
-[`align_of`]: ../std/mem/fn.align_of.html
-[`size_of`]: ../std/mem/fn.size_of.html
-[`Sized`]: ../std/marker/trait.Sized.html
-[`Copy`]: ../std/marker/trait.Copy.html
+[`align_of_val`]: std::mem::align_of_val
+[`size_of_val`]: std::mem::size_of_val
+[`align_of`]: std::mem::align_of
+[`size_of`]: std::mem::size_of
+[`Sized`]: std::marker::Sized
+[`Copy`]: std::marker::Copy
[dynamically sized types]: dynamically-sized-types.md
[field-less enums]: items/enumerations.md#field-less-enum
+[fn-abi-compatibility]: ../core/primitive.fn.md#abi-compatibility
[enumerations]: items/enumerations.md
[zero-variant enums]: items/enumerations.md#zero-variant-enums
[undefined behavior]: behavior-considered-undefined.md
@@ -618,4 +707,4 @@ used with any other representation.
[primitive representations]: #primitive-representations
[structs]: items/structs.md
[`transparent`]: #the-transparent-representation
-[`Layout`]: ../std/alloc/struct.Layout.html
+[`Layout`]: std::alloc::Layout
diff --git a/src/types.md b/src/types.md
index 0f82638..a93f93d 100644
--- a/src/types.md
+++ b/src/types.md
@@ -1,14 +1,21 @@
{{#include types-redirect.html}}
# Types
+r[type]
+
+r[type.intro]
Every variable, item, and value in a Rust program has a type. The _type_ of a
*value* defines the interpretation of the memory holding it and the operations
that may be performed on the value.
+r[type.builtin]
Built-in types are tightly integrated into the language, in nontrivial ways
-that are not possible to emulate in user-defined types. User-defined types have
-limited capabilities.
+that are not possible to emulate in user-defined types.
+
+r[type.user-defined]
+User-defined types have limited capabilities.
+r[type.kinds]
The list of types is:
* Primitive types:
@@ -37,6 +44,9 @@ The list of types is:
## Type expressions
+r[type.name]
+
+r[type.name.syntax]
> **Syntax**\
> _Type_ :\
> _TypeNoBounds_\
@@ -59,27 +69,47 @@ The list of types is:
> | [_BareFunctionType_]\
> | [_MacroInvocation_]
+r[type.name.intro]
A _type expression_ as defined in the _Type_ grammar rule above is the syntax
for referring to a type. It may refer to:
+r[type.name.sequence]
* Sequence types ([tuple], [array], [slice]).
+
+r[type.name.path]
* [Type paths] which can reference:
* Primitive types ([boolean], [numeric], [textual]).
* Paths to an [item] ([struct], [enum], [union], [type alias], [trait]).
* [`Self` path] where `Self` is the implementing type.
* Generic [type parameters].
+
+r[type.name.pointer]
* Pointer types ([reference], [raw pointer], [function pointer]).
+
+r[type.name.inference]
* The [inferred type] which asks the compiler to determine the type.
+
+r[type.name.grouped]
* [Parentheses] which are used for disambiguation.
+
+r[type.name.trait]
* Trait types: [Trait objects] and [impl trait].
+
+r[type.name.never]
* The [never] type.
+
+r[type.name.macro-expansion]
* [Macros] which expand to a type expression.
### Parenthesized types
+r[type.name.parenthesized]
+
+r[type.name.parenthesized.syntax]
> _ParenthesizedType_ :\
> `(` [_Type_] `)`
+r[type.name.parenthesized.intro]
In some situations the combination of types may be ambiguous. Use parentheses
around a type to avoid ambiguity. For example, the `+` operator for [type
boundaries] within a [reference type] is unclear where the
@@ -94,10 +124,16 @@ type T<'a> = &'a (dyn Any + Send);
## Recursive types
+r[type.recursive]
+
+r[type.recursive.intro]
Nominal types — [structs], [enumerations], and [unions] — may be
recursive. That is, each `enum` variant or `struct` or `union` field may
refer, directly or indirectly, to the enclosing `enum` or `struct` type
-itself. Such recursion has restrictions:
+itself.
+
+r[type.recursive.constraint]
+Such recursion has restrictions:
* Recursive types must include a nominal type in the recursion (not mere [type
aliases], or other structural types such as [arrays] or [tuples]). So `type
diff --git a/src/types/array.md b/src/types/array.md
index 88ea863..ef54af1 100644
--- a/src/types/array.md
+++ b/src/types/array.md
@@ -1,12 +1,18 @@
# Array types
+r[type.array]
+
+r[type.array.syntax]
> **Syntax**\
> _ArrayType_ :\
> `[` [_Type_] `;` [_Expression_] `]`
+r[type.array.intro]
An array is a fixed-size sequence of `N` elements of type `T`. The array type
-is written as `[T; N]`. The size is a [constant expression] that evaluates to a
-[`usize`].
+is written as `[T; N]`.
+
+r[type.array.constraint]
+The size is a [constant expression] that evaluates to a [`usize`].
Examples:
@@ -18,6 +24,7 @@ let array: [i32; 3] = [1, 2, 3];
let boxed_array: Box<[i32]> = Box::new([1, 2, 3]);
```
+r[type.array.index]
All elements of arrays are always initialized, and access to an array is
always bounds-checked in safe methods and operators.
@@ -26,6 +33,5 @@ always bounds-checked in safe methods and operators.
[_Expression_]: ../expressions.md
[_Type_]: ../types.md#type-expressions
-[`Vec`]: ../../std/vec/struct.Vec.html
[`usize`]: numeric.md#machine-dependent-integer-types
[constant expression]: ../const_eval.md#constant-expressions
diff --git a/src/types/boolean.md b/src/types/boolean.md
index 7ea99d1..10c6e5d 100644
--- a/src/types/boolean.md
+++ b/src/types/boolean.md
@@ -1,44 +1,61 @@
# Boolean type
+r[type.bool]
+
```rust
let b: bool = true;
```
+r[type.bool.intro]
The *boolean type* or *bool* is a primitive data type that can take on one of
two values, called *true* and *false*.
+r[type.bool.literal]
Values of this type may be created using a [literal expression] using the
keywords `true` and `false` corresponding to the value of the same name.
+r[type.bool.namespace]
This type is a part of the [language prelude] with the [name] `bool`.
-An object with the boolean type has a [size and alignment] of 1 each. The
-value false has the bit pattern `0x00` and the value true has the bit pattern
+r[type.bool.layout]
+An object with the boolean type has a [size and alignment] of 1 each.
+
+r[type.bool.repr]
+The value false has the bit pattern `0x00` and the value true has the bit pattern
`0x01`. It is [undefined behavior] for an object with the boolean type to have
any other bit pattern.
+r[type.bool.usage]
The boolean type is the type of many operands in various [expressions]:
+r[type.bool.usage-condition]
* The condition operand in [if expressions] and [while expressions]
+
+r[type.bool.usage-lazy-operator]
* The operands in [lazy boolean operator expressions][lazy]
> **Note**: The boolean type acts similarly to but is not an [enumerated type].
In practice, this mostly means that constructors are not associated to the type
(e.g. `bool::true`).
+r[type.bool.traits]
Like all primitives, the boolean type [implements][p-impl] the
[traits][p-traits] [`Clone`][p-clone], [`Copy`][p-copy], [`Sized`][p-sized],
[`Send`][p-send], and [`Sync`][p-sync].
-> **Note**: See the [standard library docs][std] for library operations.
+> **Note**: See the [standard library docs](bool) for library operations.
## Operations on boolean values
+r[type.bool.expr]
+
When using certain operator expressions with a
boolean type for its operands, they evaluate using the rules of [boolean logic].
### Logical not
+r[type.bool.expr.not]
+
| `b` | [`!b`][op-not] |
|- | - |
| `true` | `false` |
@@ -46,6 +63,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].
### Logical or
+r[type.bool.expr.or]
+
| `a` | `b` | [a | b
][op-or] |
|- | - | - |
| `true` | `true` | `true` |
@@ -55,6 +74,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].
### Logical and
+r[type.bool.expr.and]
+
| `a` | `b` | [`a & b`][op-and] |
|- | - | - |
| `true` | `true` | `true` |
@@ -64,6 +85,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].
### Logical xor
+r[type.bool.expr.xor]
+
| `a` | `b` | [`a ^ b`][op-xor] |
|- | - | - |
| `true` | `true` | `false` |
@@ -73,6 +96,9 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].
### Comparisons
+r[type.bool.expr.cmp]
+
+r[type.bool.expr.cmp.eq]
| `a` | `b` | [`a == b`][op-compare] |
|- | - | - |
| `true` | `true` | `true` |
@@ -80,6 +106,7 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].
| `false` | `true` | `false` |
| `false` | `false` | `true` |
+r[type.bool.expr.cmp.greater]
| `a` | `b` | [`a > b`][op-compare] |
|- | - | - |
| `true` | `true` | `false` |
@@ -87,13 +114,22 @@ boolean type for its operands, they evaluate using the rules of [boolean logic].
| `false` | `true` | `false` |
| `false` | `false` | `false` |
+r[type.bool.expr.cmp.not-eq]
* `a != b` is the same as `!(a == b)`
+
+r[type.bool.expr.cmp.greater-eq]
* `a >= b` is the same as `a == b | a > b`
+
+r[type.bool.expr.cmp.less]
* `a < b` is the same as `!(a >= b)`
+
+r[type.bool.expr.cmp.less-eq]
* `a <= b` is the same as `a == b | a < b`
## Bit validity
+r[type.bool.validity]
+
The single byte of a `bool` is guaranteed to be initialized (in other words,
`transmute::(...)` is always sound -- but since some bit patterns
are invalid `bool`s, the inverse is not always sound).
@@ -119,6 +155,5 @@ are invalid `bool`s, the inverse is not always sound).
[p-sync]: ../special-types-and-traits.md#sync
[p-traits]: ../items/traits.md
[size and alignment]: ../type-layout.md#size-and-alignment
-[std]: ../../std/primitive.bool.html
[undefined behavior]: ../behavior-considered-undefined.md
[while expressions]: ../expressions/loop-expr.md#predicate-loops
diff --git a/src/types/closure.md b/src/types/closure.md
index eecdb03..0f59f3f 100644
--- a/src/types/closure.md
+++ b/src/types/closure.md
@@ -1,5 +1,7 @@
# Closure types
+r[type.closure]
+
A [closure expression] produces a closure value with a unique, anonymous type
that cannot be written out. A closure type is approximately equivalent to a
struct which contains the captured variables. For instance, the following
@@ -47,6 +49,9 @@ f(Closure{s: s, t: &t});
## Capture modes
+r[type.closure.capture]
+
+r[type.closure.capture.order]
The compiler prefers to capture a closed-over variable by immutable borrow,
followed by unique immutable borrow (see below), by mutable borrow, and finally
by move. It will pick the first choice of these that is compatible with how the
@@ -54,14 +59,17 @@ captured variable is used inside the closure body. The compiler does not take
surrounding code into account, such as the lifetimes of involved variables, or
of the closure itself.
+r[type.closure.capture.move]
If the `move` keyword is used, then all captures are by move or, for `Copy`
types, by copy, regardless of whether a borrow would work. The `move` keyword is
usually used to allow the closure to outlive the captured values, such as if the
closure is being returned or used to spawn a new thread.
+r[type.closure.capture.composite]
Composite types such as structs, tuples, and enums are always captured entirely,
not by individual fields. It may be necessary to borrow into a local variable in
order to capture a single field:
+
```rust
# use std::collections::HashSet;
@@ -87,6 +95,8 @@ borrowed to iterate over, the code would not compile.
## Unique immutable borrows in captures
+r[type.closure.unique-immutable]
+
Captures can occur by a special kind of borrow called a _unique immutable
borrow_, which cannot be used anywhere else in the language and cannot be
written out explicitly. It occurs when modifying the referent of a mutable
@@ -115,13 +125,18 @@ the closure's lifetime has expired at the end of the block, releasing the borrow
## Call traits and coercions
+r[type.closure.call]
+
+r[type.closure.call.intro]
Closure types all implement [`FnOnce`], indicating that they can be called once
by consuming ownership of the closure. Additionally, some closures implement
more specific call traits:
+r[type.closure.call.fn-mut]
* A closure which does not move out of any captured variables implements
[`FnMut`], indicating that it can be called by mutable reference.
+r[type.closure.call.fn]
* A closure which does not mutate or move out of any captured variables
implements [`Fn`], indicating that it can be called by shared reference.
@@ -130,6 +145,7 @@ more specific call traits:
> closure type are determined by what the closure does with captured values,
> not how it captures them.
+r[type.closure.non-capturing]
*Non-capturing closures* are closures that don't capture anything from their
environment. They can be coerced to function pointers (e.g., `fn()`)
with the matching signature.
@@ -146,6 +162,9 @@ x = bo(5,7);
## Other traits
+r[type.closure.traits]
+
+r[type.closure.traits.intro]
All closure types implement [`Sized`]. Additionally, closure types implement the
following traits if allowed to do so by the types of the captures it stores:
@@ -154,6 +173,7 @@ following traits if allowed to do so by the types of the captures it stores:
* [`Sync`]
* [`Send`]
+r[type.closure.traits.behavior]
The rules for [`Send`] and [`Sync`] match those for normal struct types, while
[`Clone`] and [`Copy`] behave as if [derived]. For [`Clone`], the order of
cloning of the captured variables is left unspecified.
@@ -170,9 +190,6 @@ Because captures are often by reference, the following general rules arise:
[`Clone`]: ../special-types-and-traits.md#clone
[`Copy`]: ../special-types-and-traits.md#copy
-[`FnMut`]: ../../std/ops/trait.FnMut.html
-[`FnOnce`]: ../../std/ops/trait.FnOnce.html
-[`Fn`]: ../../std/ops/trait.Fn.html
[`Send`]: ../special-types-and-traits.md#send
[`Sized`]: ../special-types-and-traits.md#sized
[`Sync`]: ../special-types-and-traits.md#sync
diff --git a/src/types/enum.md b/src/types/enum.md
index 8f81fb1..a3ae287 100644
--- a/src/types/enum.md
+++ b/src/types/enum.md
@@ -1,22 +1,29 @@
# Enumerated types
+r[type.enum]
+
+r[type.enum.intro]
An *enumerated type* is a nominal, heterogeneous disjoint union type, denoted
by the name of an [`enum` item]. [^enumtype]
+r[type.enum.declaration]
An [`enum` item] declares both the type and a number of *variants*, each of
which is independently named and has the syntax of a struct, tuple struct or
unit-like struct.
+r[type.enum.constructor]
New instances of an `enum` can be constructed with a [struct expression].
+r[type.enum.value]
Any `enum` value consumes as much memory as the largest variant for its
corresponding `enum` type, as well as the size needed to store a discriminant.
+r[type.enum.name]
Enum types cannot be denoted *structurally* as types, but must be denoted by
named reference to an [`enum` item].
[^enumtype]: The `enum` type is analogous to a `data` constructor declaration in
- ML, or a *pick ADT* in Limbo.
+ Haskell, or a *pick ADT* in Limbo.
[`enum` item]: ../items/enumerations.md
[struct expression]: ../expressions/struct-expr.md
diff --git a/src/types/function-item.md b/src/types/function-item.md
index c8088e4..3aa5a24 100644
--- a/src/types/function-item.md
+++ b/src/types/function-item.md
@@ -1,13 +1,19 @@
# Function item types
+r[type.fn-item]
+
+r[type.fn-item.intro]
When referred to, a function item, or the constructor of a tuple-like struct or
-enum variant, yields a zero-sized value of its _function item type_. That type
-explicitly identifies the function - its name, its type arguments, and its
+enum variant, yields a zero-sized value of its _function item type_\1
+
+r[type.fn-item.unique]
+That type explicitly identifies the function - its name, its type arguments, and its
early-bound lifetime arguments (but not its late-bound lifetime arguments,
which are only assigned when the function is called) - so the value does not
need to contain an actual function pointer, and no indirection is needed when
the function is called.
+r[type.fn-item.name]
There is no syntax that directly refers to a function item type, but the
compiler will display the type as something like `fn(u32) -> i32 {fn_name}` in
error messages.
@@ -22,6 +28,7 @@ let x = &mut foo::;
*x = foo::; //~ ERROR mismatched types
```
+r[type.fn-item.coercion]
However, there is a [coercion] from function items to [function pointers] with
the same signature, which is triggered not only when a function item is used
when a function pointer is directly expected, but also when different function
@@ -43,14 +50,12 @@ let foo_ptr_2 = if want_i32 {
};
```
+r[type.fn-item.traits]
All function items implement [`Fn`], [`FnMut`], [`FnOnce`], [`Copy`],
[`Clone`], [`Send`], and [`Sync`].
[`Clone`]: ../special-types-and-traits.md#clone
[`Copy`]: ../special-types-and-traits.md#copy
-[`FnMut`]: ../../std/ops/trait.FnMut.html
-[`FnOnce`]: ../../std/ops/trait.FnOnce.html
-[`Fn`]: ../../std/ops/trait.Fn.html
[`Send`]: ../special-types-and-traits.md#send
[`Sync`]: ../special-types-and-traits.md#sync
[coercion]: ../type-coercions.md
diff --git a/src/types/function-pointer.md b/src/types/function-pointer.md
index 82103be..3fbe207 100644
--- a/src/types/function-pointer.md
+++ b/src/types/function-pointer.md
@@ -1,5 +1,8 @@
# Function pointer types
+r[type.fn-pointer]
+
+r[type.fn-pointer.syntax]
> **Syntax**\
> _BareFunctionType_ :\
> [_ForLifetimes_]? _FunctionTypeQualifiers_ `fn`\
@@ -23,13 +26,18 @@
> _MaybeNamedFunctionParametersVariadic_ :\
> ( _MaybeNamedParam_ `,` )\* _MaybeNamedParam_ `,` [_OuterAttribute_]\* `...`
+r[type.fn-pointer.intro]
Function pointer types, written using the `fn` keyword, refer to a function
-whose identity is not necessarily known at compile-time. They can be created
-via a coercion from both [function items] and non-capturing [closures].
+whose identity is not necessarily known at compile-time.
+
+r[type.fn-pointer.coercion]
+They can be created via a coercion from both [function items] and non-capturing [closures].
+r[type.fn-pointer.qualifiers]
The `unsafe` qualifier indicates that the type's value is an [unsafe
function], and the `extern` qualifier indicates it is an [extern function].
+r[type.fn-pointer.constraint-variadic]
Variadic parameters can only be specified with [`extern`] function types with
the `"C"` or `"cdecl"` calling convention.
@@ -49,6 +57,8 @@ x = bo(5,7);
## Attributes on function pointer parameters
+r[type.fn-pointer.attributes]
+
Attributes on function pointer parameters follow the same rules and
restrictions as [regular function parameters].
diff --git a/src/types/impl-trait.md b/src/types/impl-trait.md
index 7e99949..5a91334 100644
--- a/src/types/impl-trait.md
+++ b/src/types/impl-trait.md
@@ -1,10 +1,14 @@
# Impl trait
+r[type.impl-trait]
+
+r[type.impl-trait.syntax]
> **Syntax**\
> _ImplTraitType_ : `impl` [_TypeParamBounds_]
>
> _ImplTraitTypeOneBound_ : `impl` [_TraitBound_]
+r[type.impl-trait.intro]
`impl Trait` provides ways to specify unnamed but concrete types that
implement a specific trait.
It can appear in two sorts of places: argument position (where it can act as an anonymous type parameter to functions), and return position (where it can act as an abstract return type).
@@ -23,9 +27,12 @@ fn bar() -> impl Trait {
```
## Anonymous type parameters
+r[type.impl-trait.param]
+
> Note: This is often called "impl Trait in argument position".
(The term "parameter" is more correct here, but "impl Trait in argument position" is the phrasing used during the development of this feature, and it remains in parts of the implementation.)
+r[type.impl-trait.param.intro]
Functions can use `impl` followed by a set of trait bounds to declare a parameter as having an anonymous type.
The caller must provide a type that satisfies the bounds declared by the anonymous type parameter, and the function can only use the methods available through the trait bounds of the anonymous type parameter.
@@ -43,6 +50,7 @@ fn with_impl_trait(arg: impl Trait) {
}
```
+r[type.impl-trait.param.generic]
That is, `impl Trait` in argument position is syntactic sugar for a generic type parameter like ``, except that the type is anonymous and doesn't appear in the [_GenericParams_] list.
> **Note:**
@@ -52,10 +60,15 @@ That is, `impl Trait` in argument position is syntactic sugar for a generic type
## Abstract return types
+r[type.impl-trait.return]
+
> Note: This is often called "impl Trait in return position".
+r[type.impl-trait.return.intro]
Functions can use `impl Trait` to return an abstract return type.
These types stand in for another concrete type where the caller may only use the methods declared by the specified `Trait`.
+
+r[type.impl-trait.return.constraint-body]
Each possible return value from the function must resolve to the same concrete type.
`impl Trait` in return position allows a function to return an unboxed abstract type.
@@ -87,22 +100,38 @@ Returning `impl Iterator` means that a function only exposes the `Iterator` trai
## Return-position `impl Trait` in traits and trait implementations
+r[type.impl-trait.return-in-trait]
+
+r[type.impl-trait.return-in-trait.intro]
Functions in traits may also use `impl Trait` as a syntax for an anonymous associated type.
+r[type.impl-trait.return-in-trait.desugaring]
Every `impl Trait` in the return type of an associated function in a trait is desugared to an anonymous associated type. The return type that appears in the implementation's function signature is used to determine the value of the associated type.
## Capturing
+r[type.impl-trait.generic-captures]
+
Behind each return-position `impl Trait` abstract type is some hidden concrete type. For this concrete type to use a generic parameter, that generic parameter must be *captured* by the abstract type.
## Automatic capturing
+r[type.impl-trait.generic-capture.auto]
+
+r[type.impl-trait.generic-capture.auto.intro]
Return-position `impl Trait` abstract types automatically capture certain of the in-scope generic parameters. Everywhere, these automatically capture all in-scope type and const generic parameters.
-On items of trait impls and trait definitions, these types additionally automatically capture all in-scope generic lifetime parameters, including higher-ranked ones. On free functions and on associated functions and methods of inherent impls, only the generic lifetime parameters that appear in the bounds of abstract return type are captured.
+r[type.impl-trait.generic-capture.auto.trait]
+On items of trait impls and trait definitions, these types additionally automatically capture all in-scope generic lifetime parameters, including higher-ranked ones\1
+
+r[type.impl-trait.generic-capture.auto.fn]
+On free functions and on associated functions and methods of inherent impls, only the generic lifetime parameters that appear in the bounds of abstract return type are captured.
## Precise capturing
+r[type.impl-trait.generic-capture.precise]
+
+r[type.impl-trait.generic-capture.precise.use]
The set of generic parameters captured by a return-position `impl Trait` abstract type may be explicitly controlled with a [`use<..>` bound]. If present, only the generic parameters listed in the `use<..>` bound will be captured. E.g.:
```rust
@@ -113,8 +142,13 @@ fn capture<'a, 'b, T>(x: &'a (), y: T) -> impl Sized + use<'a, T> {
}
```
-Currently, only one `use<..>` bound may be present in a bounds list, such bounds are not allowed in the signature of items of a trait definition, all in-scope type and const generic parameters must be included, and all lifetime parameters that appear in other bounds of the abstract type must be included. Within the `use<..>` bound, any lifetime parameters present must appear before all type and const generic parameters, and the elided lifetime (`'_`) may be present if it is otherwise allowed to appear within the `impl Trait` return type.
+r[type.impl-trait.generic-capture.precise.constraint-single]
+Currently, only one `use<..>` bound may be present in a bounds list, such bounds are not allowed in the signature of items of a trait definition, all in-scope type and const generic parameters must be included, and all lifetime parameters that appear in other bounds of the abstract type must be included\1
+r[type.impl-trait.generic-capture.precise.constraint-lifetime]
+Within the `use<..>` bound, any lifetime parameters present must appear before all type and const generic parameters, and the elided lifetime (`'_`) may be present if it is otherwise allowed to appear within the `impl Trait` return type.
+
+r[type.impl-trait.generic-capture.precise.constraint-param-impl-trait]
Because all in-scope type parameters must be included by name, a `use<..>` bound may not be used in the signature of items that use argument-position `impl Trait`, as those items have anonymous type parameters in scope.
## Differences between generics and `impl Trait` in return position
@@ -150,6 +184,8 @@ Instead, the function chooses the return type, but only promises that it will im
## Limitations
+r[type.impl-trait.constraint]
+
`impl Trait` can only appear as a parameter or return type of a non-`extern` function.
It cannot be the type of a `let` binding, field type, or appear inside a type alias.
diff --git a/src/types/inferred.md b/src/types/inferred.md
index c33ebd9..7179826 100644
--- a/src/types/inferred.md
+++ b/src/types/inferred.md
@@ -1,11 +1,19 @@
# Inferred type
+r[type.inferred]
+
+r[type.inferred.syntax]
> **Syntax**\
> _InferredType_ : `_`
+r[type.inferred.intro]
The inferred type asks the compiler to infer the type if possible based on the
-surrounding information available. It cannot be used in item signatures. It is
-often used in generic arguments:
+surrounding information available.
+
+r[type.inferred.constraint]
+It cannot be used in item signatures.
+
+It is often used in generic arguments:
```rust
let x: Vec<_> = (0..10).collect();
diff --git a/src/types/never.md b/src/types/never.md
index 3fbd2ad..702281d 100644
--- a/src/types/never.md
+++ b/src/types/never.md
@@ -1,12 +1,19 @@
# Never type
+r[type.never]
+
+r[type.never.syntax]
> **Syntax**\
> _NeverType_ : `!`
+r[type.never.intro]
The never type `!` is a type with no values, representing the result of
-computations that never complete. Expressions of type `!` can be coerced into
-any other type.
+computations that never complete.
+
+r[type.never.coercion]
+Expressions of type `!` can be coerced into any other type.
+r[type.never.constraint]
The `!` type can **only** appear in function return types presently,
indicating it is a diverging function that never returns.
@@ -17,7 +24,7 @@ fn foo() -> ! {
```
```rust
-extern "C" {
- pub fn no_return_extern_func() -> !;
+unsafe extern "C" {
+ pub safe fn no_return_extern_func() -> !;
}
```
diff --git a/src/types/numeric.md b/src/types/numeric.md
index bd59daa..88178d1 100644
--- a/src/types/numeric.md
+++ b/src/types/numeric.md
@@ -1,7 +1,12 @@
# Numeric types
+r[type.numeric]
+
## Integer types
+r[type.numeric.int]
+
+r[type.numeric.int.unsigned]
The unsigned integer types consist of:
Type | Minimum | Maximum
@@ -12,6 +17,7 @@ Type | Minimum | Maximum
`u64` | 0 | 264-1
`u128` | 0 | 2128-1
+r[type.numeric.int.signed]
The signed two's complement integer types consist of:
Type | Minimum | Maximum
@@ -25,20 +31,27 @@ Type | Minimum | Maximum
## Floating-point types
+r[type.numeric.float]
+
The IEEE 754-2008 "binary32" and "binary64" floating-point types are `f32` and
`f64`, respectively.
## Machine-dependent integer types
+r[type.numeric.int.size]
+
+r[type.numeric.int.size.usize]
The `usize` type is an unsigned integer type with the same number of bits as the
platform's pointer type. It can represent every memory address in the process.
+r[type.numeric.int.size.isize]
The `isize` type is a signed integer type with the same number of bits as the
platform's pointer type. The theoretical upper bound on object and array size
is the maximum `isize` value. This ensures that `isize` can be used to calculate
differences between pointers into an object or array and can address every byte
within an object along with one byte past the end.
+r[type.numeric.int.size.minimum]
`usize` and `isize` are at least 16-bits wide.
> **Note**: Many pieces of Rust code may assume that pointers, `usize`, and
@@ -48,5 +61,7 @@ within an object along with one byte past the end.
## Bit validity
+r[type.numeric.validity]
+
For every numeric type, `T`, the bit validity of `T` is equivalent to the bit
validity of `[u8; size_of::()]`. An uninitialized byte is not a valid `u8`.
diff --git a/src/types/parameters.md b/src/types/parameters.md
index 7b9e7e6..89b7df9 100644
--- a/src/types/parameters.md
+++ b/src/types/parameters.md
@@ -1,5 +1,7 @@
# Type parameters
+r[type.generic]
+
Within the body of an item that has type parameter declarations, the names of
its type parameters are types:
diff --git a/src/types/pointer.md b/src/types/pointer.md
index cbbf356..0f24d6b 100644
--- a/src/types/pointer.md
+++ b/src/types/pointer.md
@@ -1,67 +1,100 @@
# Pointer types
+r[type.pointer]
+
+r[type.pointer.intro]
All pointers are explicit first-class values.
They can be moved or copied, stored into data structs, and returned from functions.
## References (`&` and `&mut`)
+r[type.pointer.reference]
+
+r[type.pointer.reference.syntax]
> **Syntax**\
> _ReferenceType_ :\
> `&` [_Lifetime_]? `mut`? [_TypeNoBounds_]
### Shared references (`&`)
+r[type.pointer.reference.shared]
+
+r[type.pointer.reference.shared.intro]
Shared references point to memory which is owned by some other value.
+
+r[type.pointer.reference.shared.constraint-mutation]
When a shared reference to a value is created, it prevents direct mutation of the value.
[Interior mutability] provides an exception for this in certain circumstances.
As the name suggests, any number of shared references to a value may exist.
A shared reference type is written `&type`, or `&'a type` when you need to specify an explicit lifetime.
+
+r[type.pointer.reference.shared.copy]
Copying a reference is a "shallow" operation:
it involves only copying the pointer itself, that is, pointers are `Copy`.
Releasing a reference has no effect on the value it points to, but referencing of a [temporary value] will keep it alive during the scope of the reference itself.
### Mutable references (`&mut`)
+r[type.pointer.reference.mut]
+
+r[type.pointer.reference.mut.intro]
Mutable references point to memory which is owned by some other value.
A mutable reference type is written `&mut type` or `&'a mut type`.
+
+r[type.pointer.reference.mut.copy]
A mutable reference (that hasn't been borrowed) is the only way to access the value it points to, so is not `Copy`.
## Raw pointers (`*const` and `*mut`)
+r[type.pointer.raw]
+
+r[type.pointer.raw.syntax]
> **Syntax**\
> _RawPointerType_ :\
> `*` ( `mut` | `const` ) [_TypeNoBounds_]
+r[type.pointer.raw.intro]
Raw pointers are pointers without safety or liveness guarantees.
Raw pointers are written as `*const T` or `*mut T`.
For example `*const i32` means a raw pointer to a 32-bit integer.
+
+r[type.pointer.raw.copy]
Copying or dropping a raw pointer has no effect on the lifecycle of any other value.
+
+r[type.pointer.raw.safety]
Dereferencing a raw pointer is an [`unsafe` operation].
+
This can also be used to convert a raw pointer to a reference by reborrowing it (`&*` or `&mut *`).
Raw pointers are generally discouraged;
they exist to support interoperability with foreign code, and writing performance-critical or low-level functions.
+r[type.pointer.raw.cmp]
When comparing raw pointers they are compared by their address, rather than by what they point to.
When comparing raw pointers to [dynamically sized types] they also have their additional data compared.
-Raw pointers can be created directly using [`core::ptr::addr_of!`] for `*const` pointers and [`core::ptr::addr_of_mut!`] for `*mut` pointers.
+r[type.pointer.raw.constructor]
+Raw pointers can be created directly using `&raw const` for `*const` pointers and `&raw mut` for `*mut` pointers.
## Smart Pointers
+r[type.pointer.smart]
+
The standard library contains additional 'smart pointer' types beyond references and raw pointers.
## Bit validity
+r[type.pointer.validity]
+
+r[type.pointer.validity.pointer-fragment]
Despite pointers and references being similar to `usize`s in the machine code emitted on most platforms,
the semantics of transmuting a reference or pointer type to a non-pointer type is currently undecided.
Thus, it may not be valid to transmute a pointer or reference type, `P`, to a `[u8; size_of::()]`.
+r[type.pointer.validity.raw]
For thin raw pointers (i.e., for `P = *const T` or `P = *mut T` for `T: Sized`),
the inverse direction (transmuting from an integer or array of integers to `P`) is always valid.
However, the pointer produced via such a transmutation may not be dereferenced (not even if `T` has size zero).
-[`core::ptr::addr_of!`]: ../../core/ptr/macro.addr_of.html
-[`core::ptr::addr_of_mut!`]: ../../core/ptr/macro.addr_of_mut.html
[Interior mutability]: ../interior-mutability.md
[_Lifetime_]: ../trait-bounds.md
[_TypeNoBounds_]: ../types.md#type-expressions
diff --git a/src/types/slice.md b/src/types/slice.md
index 6ba5e7d..79c340a 100644
--- a/src/types/slice.md
+++ b/src/types/slice.md
@@ -1,12 +1,17 @@
# Slice types
+r[type.slice]
+
+r[type.slice.syntax]
> **Syntax**\
> _SliceType_ :\
> `[` [_Type_] `]`
+r[type.slice.intro]
A slice is a [dynamically sized type] representing a 'view' into a sequence of
elements of type `T`. The slice type is written as `[T]`.
+r[type.slice.unsized]
Slice types are generally used through pointer types. For example:
* `&[T]`: a 'shared slice', often just called a 'slice'. It doesn't own the
@@ -24,6 +29,7 @@ let boxed_array: Box<[i32]> = Box::new([1, 2, 3]);
let slice: &[i32] = &boxed_array[..];
```
+r[type.slice.safe]
All elements of slices are always initialized, and access to a slice is always
bounds-checked in safe methods and operators.
diff --git a/src/types/struct.md b/src/types/struct.md
index 1f20dbb..6a672f7 100644
--- a/src/types/struct.md
+++ b/src/types/struct.md
@@ -1,22 +1,30 @@
# Struct types
+r[type.struct]
+
+r[type.struct.intro]
A `struct` *type* is a heterogeneous product of other types, called the
*fields* of the type.[^structtype]
+r[type.struct.constructor]
New instances of a `struct` can be constructed with a [struct expression].
+r[type.struct.layout]
The memory layout of a `struct` is undefined by default to allow for compiler
optimizations like field reordering, but it can be fixed with the
[`repr` attribute]. In either case, fields may be given in any order in a
corresponding struct *expression*; the resulting `struct` value will always
have the same memory layout.
+r[type.struct.field-visibility]
The fields of a `struct` may be qualified by [visibility modifiers], to allow
access to data in a struct outside a module.
+r[type.struct.tuple]
A _tuple struct_ type is just like a struct type, except that the fields are
anonymous.
+r[type.struct.unit]
A _unit-like struct_ type is like a struct type, except that it has no fields.
The one value constructed by the associated [struct expression] is the only
value that inhabits such a type.
diff --git a/src/types/textual.md b/src/types/textual.md
index fcbec08..e851533 100644
--- a/src/types/textual.md
+++ b/src/types/textual.md
@@ -1,30 +1,43 @@
# Textual types
+r[type.text]
+
+r[type.text.intro]
The types `char` and `str` hold textual data.
+r[type.text.char-value]
A value of type `char` is a [Unicode scalar value] (i.e. a code point that is
not a surrogate), represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF
-or 0xE000 to 0x10FFFF range. It is immediate [Undefined Behavior] to create a
+or 0xE000 to 0x10FFFF range.
+
+r[type.text.char-precondition]
+It is immediate [undefined behavior] to create \1
`char` that falls outside this range. A `[char]` is effectively a UCS-4 / UTF-32
string of length 1.
+r[type.text.str-value]
A value of type `str` is represented the same way as `[u8]`, a slice of
8-bit unsigned bytes. However, the Rust standard library makes extra assumptions
about `str`: methods working on `str` assume and ensure that the data in there
is valid UTF-8. Calling a `str` method with a non-UTF-8 buffer can cause
-[Undefined Behavior] now or in the future.
+[undefined behavior] now or in the future.
+r[type.text.str-unsized]
Since `str` is a [dynamically sized type], it can only be instantiated through a
pointer type, such as `&str`.
## Layout and bit validity
+r[type.text.layout]
+
+r[type.layout.char-layout]
`char` is guaranteed to have the same size and alignment as `u32` on all platforms.
+r[type.layout.char-validity]
Every byte of a `char` is guaranteed to be initialized (in other words,
`transmute::()]>(...)` is always sound -- but since
some bit patterns are invalid `char`s, the inverse is not always sound).
[Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
-[Undefined Behavior]: ../behavior-considered-undefined.md
+[undefined behavior]: ../behavior-considered-undefined.md
[dynamically sized type]: ../dynamically-sized-types.md
diff --git a/src/types/trait-object.md b/src/types/trait-object.md
index 3526b7a..0c4c759 100644
--- a/src/types/trait-object.md
+++ b/src/types/trait-object.md
@@ -1,5 +1,8 @@
# Trait objects
+r[type.trait-object]
+
+r[type.trait-object.syntax]
> **Syntax**\
> _TraitObjectType_ :\
> `dyn`? [_TypeParamBounds_]
@@ -7,16 +10,21 @@
> _TraitObjectTypeOneBound_ :\
> `dyn`? [_TraitBound_]
+r[type.trait-object.intro]
A *trait object* is an opaque value of another type that implements a set of
-traits. The set of traits is made up of an [object safe] *base trait* plus any
+traits. The set of traits is made up of a [dyn compatible] *base trait* plus any
number of [auto traits].
+r[type.trait-object.impls]
Trait objects implement the base trait, its auto traits, and any [supertraits]
of the base trait.
+r[type.trait-object.name]
Trait objects are written as the keyword `dyn` followed by a set of trait
-bounds, but with the following restrictions on the trait bounds. All traits
-except the first trait must be auto traits, there may not be more than one
+bounds, but with the following restrictions on the trait bounds.
+
+r[type.trait-object.constraint]
+There may not be more than one non-auto trait, no more than one
lifetime, and opt-out bounds (e.g. `?Sized`) are not allowed. Furthermore,
paths to traits may be parenthesized.
@@ -31,13 +39,15 @@ For example, given a trait `Trait`, the following are all trait objects:
* `dyn 'static + Trait`.
* `dyn (Trait)`
-> **Edition Differences**: Before the 2021 edition, the `dyn` keyword may be
+r[type.trait-object.syntax-edition2021]
+> **Edition differences**: Before the 2021 edition, the `dyn` keyword may be
> omitted.
>
> Note: For clarity, it is recommended to always use the `dyn` keyword on your
> trait objects unless your codebase supports compiling with Rust 1.26 or lower.
-> **Edition Differences**: In the 2015 edition, if the first bound of the
+r[type.trait-object.syntax-edition2015]
+> **Edition differences**: In the 2015 edition, if the first bound of the
> trait object is a path that starts with `::`, then the `dyn` will be treated
> as a part of the path. The first path can be put in parenthesis to get
> around this. As such, if you want a trait object with the trait
@@ -46,11 +56,13 @@ For example, given a trait `Trait`, the following are all trait objects:
> Beginning in the 2018 edition, `dyn` is a true keyword and is not allowed in
> paths, so the parentheses are not necessary.
+r[type.trait-object.alias]
Two trait object types alias each other if the base traits alias each other and
if the sets of auto traits are the same and the lifetime bounds are the same.
For example, `dyn Trait + Send + UnwindSafe` is the same as
`dyn Trait + UnwindSafe + Send`.
+r[type.trait-object.unsized]
Due to the opaqueness of which concrete type the value is of, trait objects are
[dynamically sized types]. Like all
DSTs, trait objects are used
@@ -93,6 +105,8 @@ type signature of `print`, and the cast expression in `main`.
## Trait Object Lifetime Bounds
+r[type.trait-object.lifetime-bounds]
+
Since a trait object can contain references, the lifetimes of those references
need to be expressed as part of the trait object. This lifetime is written as
`Trait + 'a`. There are [defaults] that allow this lifetime to usually be
@@ -102,6 +116,6 @@ inferred with a sensible choice.
[_TypeParamBounds_]: ../trait-bounds.md
[auto traits]: ../special-types-and-traits.md#auto-traits
[defaults]: ../lifetime-elision.md#default-trait-object-lifetimes
+[dyn compatible]: ../items/traits.md#dyn-compatibility
[dynamically sized types]: ../dynamically-sized-types.md
-[object safe]: ../items/traits.md#object-safety
[supertraits]: ../items/traits.md#supertraits
diff --git a/src/types/tuple.md b/src/types/tuple.md
index 804d8a0..073fbd1 100644
--- a/src/types/tuple.md
+++ b/src/types/tuple.md
@@ -1,26 +1,35 @@
# Tuple types
+r[type.tuple]
+
+r[type.tuple.syntax]
> **Syntax**\
> _TupleType_ :\
> `(` `)`\
> | `(` ( [_Type_] `,` )+ [_Type_]? `)`
+r[type.tuple.intro]
*Tuple types* are a family of structural types[^1] for heterogeneous lists of other types.
The syntax for a tuple type is a parenthesized, comma-separated list of types.
+
+r[type.tuple.restriction]
1-ary tuples require a comma after their element type to be disambiguated with a [parenthesized type].
+r[type.tuple.field-number]
A tuple type has a number of fields equal to the length of the list of types.
This number of fields determines the *arity* of the tuple.
A tuple with `n` fields is called an *n-ary tuple*.
For example, a tuple with 2 fields is a 2-ary tuple.
+r[type.tuple.field-name]
Fields of tuples are named using increasing numeric names matching their position in the list of types.
The first field is `0`.
The second field is `1`.
And so on.
The type of each field is the type of the same position in the tuple's list of types.
+r[type.tuple.unit]
For convenience and historical reasons, the tuple type with no fields (`()`) is often called *unit* or *the unit type*.
Its one value is also called *unit* or *the unit value*.
@@ -33,8 +42,11 @@ Some examples of tuple types:
* `(i32, String)` (different type from the previous example)
* `(i32, f64, Vec, Option)`
+r[type.tuple.constructor]
Values of this type are constructed using a [tuple expression].
Furthermore, various expressions will produce the unit value if there is no other meaningful value for it to evaluate to.
+
+r[type.tuple.access]
Tuple fields can be accessed by either a [tuple index expression] or [pattern matching].
[^1]: Structural types are always equivalent if their internal types are equivalent.
diff --git a/src/types/union.md b/src/types/union.md
index 326e720..c8801ee 100644
--- a/src/types/union.md
+++ b/src/types/union.md
@@ -1,19 +1,28 @@
# Union types
+r[type.union]
+
+r[type.union.intro]
A *union type* is a nominal, heterogeneous C-like union, denoted by the name of
a [`union` item][item].
+r[type.union.access]
Unions have no notion of an "active field". Instead, every union access
transmutes parts of the content of the union to the type of the accessed field.
+
+r[type.union.safety]
Since transmutes can cause unexpected or undefined behaviour, `unsafe` is
-required to read from a union field. Union field types are also restricted to a
+required to read from a union field.
+
+r[type.union.constraint]
+Union field types are also restricted to a
subset of types which ensures that they never need dropping. See the [item]
documentation for further details.
+r[type.union.layout]
The memory layout of a `union` is undefined by default (in particular, fields do
*not* have to be at offset 0), but the `#[repr(...)]` attribute can be used to
fix a layout.
[`Copy`]: ../special-types-and-traits.md#copy
-[`ManuallyDrop`]: ../../std/mem/struct.ManuallyDrop.html
[item]: ../items/unions.md
diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md
index a29fc94..232fcca 100644
--- a/src/unsafe-keyword.md
+++ b/src/unsafe-keyword.md
@@ -1,26 +1,38 @@
# The `unsafe` keyword
+r[unsafe]
+
+r[unsafe.intro]
The `unsafe` keyword can occur in several different contexts:
-unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), and unsafe trait implementations (`unsafe impl`).
+unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), unsafe trait implementations (`unsafe impl`), unsafe external blocks (`unsafe extern`), and unsafe attributes (`#[unsafe(attr)]`).
It plays several different roles, depending on where it is used and whether the `unsafe_op_in_unsafe_fn` lint is enabled:
- it is used to mark code that *defines* extra safety conditions (`unsafe fn`, `unsafe trait`)
-- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`])
+- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`], `unsafe extern`, `#[unsafe(attr)]`)
The following discusses each of these cases.
See the [keyword documentation][keyword] for some illustrative examples.
## Unsafe functions (`unsafe fn`)
+r[unsafe.fn]
+
+r[unsafe.fn.intro]
Unsafe functions are functions that are not safe in all contexts and/or for all possible inputs.
We say they have *extra safety conditions*, which are requirements that must be upheld by all callers and that the compiler does not check.
For example, [`get_unchecked`] has the extra safety condition that the index must be in-bounds.
The unsafe function should come with documentation explaining what those extra safety conditions are.
+r[unsafe.fn.safety]
Such a function must be prefixed with the keyword `unsafe` and can only be called from inside an `unsafe` block, or inside `unsafe fn` without the [`unsafe_op_in_unsafe_fn`] lint.
## Unsafe blocks (`unsafe {}`)
+r[unsafe.block]
+
+r[unsafe.block.intro]
A block of code can be prefixed with the `unsafe` keyword, to permit calling `unsafe` functions or dereferencing raw pointers.
+
+r[unsafe.block.fn-body]
By default, the body of an unsafe function is also considered to be an unsafe block;
this can be changed by enabling the [`unsafe_op_in_unsafe_fn`] lint.
@@ -41,18 +53,40 @@ By using `unsafe` blocks to represent the reverse links as raw pointers, it can
## Unsafe traits (`unsafe trait`)
+r[unsafe.trait]
+
+r[unsafe.trait.intro]
An unsafe trait is a trait that comes with extra safety conditions that must be upheld by *implementations* of the trait.
The unsafe trait should come with documentation explaining what those extra safety conditions are.
+r[unsafe.trait.safety]
Such a trait must be prefixed with the keyword `unsafe` and can only be implemented by `unsafe impl` blocks.
## Unsafe trait implementations (`unsafe impl`)
+r[unsafe.impl]
+
When implementing an unsafe trait, the implementation needs to be prefixed with the `unsafe` keyword.
By writing `unsafe impl`, the programmer states that they have taken care of satisfying the extra safety conditions required by the trait.
Unsafe trait implementations are the logical dual to unsafe traits: where unsafe traits define a proof obligation that implementations must uphold, unsafe implementations state that all relevant proof obligations have been discharged.
[keyword]: ../std/keyword.unsafe.html
-[`get_unchecked`]: ../std/primitive.slice.html#method.get_unchecked
+[`get_unchecked`]: slice::get_unchecked
[`unsafe_op_in_unsafe_fn`]: ../rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn
+
+## Unsafe external blocks (`unsafe extern`)
+
+r[unsafe.extern]
+
+The programmer who declares an [external block] must assure that the signatures of the items contained within are correct. Failing to do so may lead to undefined behavior. That this obligation has been met is indicated by writing `unsafe extern`.
+
+[external block]: items/external-blocks.md
+
+## Unsafe attributes (`#[unsafe(attr)]`)
+
+r[unsafe.attribute]
+
+An [unsafe attribute] is one that has extra safety conditions that must be upheld when using the attribute. The compiler cannot check whether these conditions have been upheld. To assert that they have been, these attributes must be wrapped in `unsafe(..)`, e.g. `#[unsafe(no_mangle)]`.
+
+[unsafe attribute]: attributes.md
diff --git a/src/unsafety.md b/src/unsafety.md
index 915fa5b..daa6834 100644
--- a/src/unsafety.md
+++ b/src/unsafety.md
@@ -1,19 +1,40 @@
# Unsafety
+r[safety]
+
+r[safety.intro]
Unsafe operations are those that can potentially violate the memory-safety
guarantees of Rust's static semantics.
+r[safety.unsafe-ops]
The following language level features cannot be used in the safe subset of
Rust:
+r[safety.unsafe-deref]
- Dereferencing a [raw pointer].
+
+r[safety.unsafe-static]
- Reading or writing a [mutable] or [external] static variable.
+
+r[safety.unsafe-union-access]
- Accessing a field of a [`union`], other than to assign to it.
+
+r[safety.unsafe-call]
- Calling an unsafe function (including an intrinsic or foreign function).
+
+r[safety.unsafe-impl]
- Implementing an [unsafe trait].
+r[safety.unsafe-extern]
+- Declaring an [`extern`] block.
+
+r[safety.unsafe-attribute]
+- Applying an [unsafe attribute] to an item.
+
+[`extern`]: items/external-blocks.md
[`union`]: items/unions.md
[mutable]: items/static-items.md#mutable-statics
[external]: items/external-blocks.md
[raw pointer]: types/pointer.md
[unsafe trait]: items/traits.md#unsafe-traits
+[unsafe attribute]: attributes.md
diff --git a/src/variables.md b/src/variables.md
index 5e5ec1b..0e22af6 100644
--- a/src/variables.md
+++ b/src/variables.md
@@ -1,20 +1,27 @@
# Variables
+r[variable]
+
+r[variable.intro]
A _variable_ is a component of a stack frame, either a named function parameter,
an anonymous [temporary](expressions.md#temporaries), or a named local
variable.
+r[variable.local]
A _local variable_ (or *stack-local* allocation) holds a value directly,
allocated within the stack's memory. The value is a part of the stack frame.
+r[variable.local-mut]
Local variables are immutable unless declared otherwise. For example:
`let mut x = ...`.
+r[variable.param-mut]
Function parameters are immutable unless declared with `mut`. The `mut` keyword
applies only to the following parameter. For example: `|mut x, y|` and
`fn f(mut x: Box, y: Box)` declare one mutable variable `x` and one
immutable variable `y`.
+r[variable.init]
Local variables are not initialized when allocated. Instead, the entire frame
worth of local variables are allocated, on frame-entry, in an uninitialized
state. Subsequent statements within a function may or may not initialize the
diff --git a/src/visibility-and-privacy.md b/src/visibility-and-privacy.md
index df9f05a..58e4b96 100644
--- a/src/visibility-and-privacy.md
+++ b/src/visibility-and-privacy.md
@@ -1,5 +1,8 @@
# Visibility and Privacy
+r[vis]
+
+r[vis.syntax]
> **Syntax**\
> _Visibility_ :\
> `pub`\
@@ -8,20 +11,24 @@
> | `pub` `(` `super` `)`\
> | `pub` `(` `in` [_SimplePath_] `)`
+r[vis.intro]
These two terms are often used interchangeably, and what they are attempting to
convey is the answer to the question "Can this item be used at this location?"
+r[vis.name-hierarchy]
Rust's name resolution operates on a global hierarchy of namespaces. Each level
in the hierarchy can be thought of as some item. The items are one of those
mentioned above, but also include external crates. Declaring or defining a new
module can be thought of as inserting a new tree into the hierarchy at the
location of the definition.
+r[vis.privacy]
To control whether interfaces can be used across modules, Rust checks each use
of an item to see whether it should be allowed or not. This is where privacy
warnings are generated, or otherwise "you used a private item of another module
and weren't allowed to."
+r[vis.default]
By default, everything is *private*, with two exceptions: Associated
items in a `pub` Trait are public by default; Enum variants
in a `pub` enum are also public by default. When an item is declared as `pub`,
@@ -44,6 +51,7 @@ pub enum State {
}
```
+r[vis.access]
With the notion of an item being either public or private, Rust allows item
accesses in two cases:
@@ -78,8 +86,10 @@ explain, here's a few use cases and what they would entail:
In the second case, it mentions that a private item "can be accessed" by the
current module and its descendants, but the exact meaning of accessing an item
-depends on what the item is. Accessing a module, for example, would mean
-looking inside of it (to import more items). On the other hand, accessing a
+depends on what the item is.
+
+r[vis.usage]
+Accessing a module, for example, would mean looking inside of it (to import more items). On the other hand, accessing a
function would mean that it is invoked. Additionally, path expressions and
import statements are considered to access an item in the sense that the
import/expression is only valid if the destination is in the current visibility
@@ -144,18 +154,31 @@ expressions, types, etc.
## `pub(in path)`, `pub(crate)`, `pub(super)`, and `pub(self)`
+r[vis.scoped]
+
+r[vis.scoped.intro]
In addition to public and private, Rust allows users to declare an item as
visible only within a given scope. The rules for `pub` restrictions are as
follows:
-- `pub(in path)` makes an item visible within the provided `path`. `path` must
-be an ancestor module of the item whose visibility is being declared.
+
+r[vis.scoped.in]
+- `pub(in path)` makes an item visible within the provided `path`.
+ `path` must be a simple path which resolves to an ancestor module of the item whose visibility is being declared.
+ Each identifier in `path` must refer directly to a module (not to a name introduced by a `use` statement).
+
+r[vis.scoped.crate]
- `pub(crate)` makes an item visible within the current crate.
+
+r[vis.scoped.super]
- `pub(super)` makes an item visible to the parent module. This is equivalent
to `pub(in super)`.
+
+r[vis.scoped.self]
- `pub(self)` makes an item visible to the current module. This is equivalent
to `pub(in self)` or not using `pub` at all.
-> **Edition Differences**: Starting with the 2018 edition, paths for
+r[vis.scoped.edition2018]
+> **Edition differences**: Starting with the 2018 edition, paths for
> `pub(in path)` must start with `crate`, `self`, or `super`. The 2015 edition
> may also use paths starting with `::` or modules from the crate root.
@@ -218,6 +241,9 @@ fn main() { bar() }
## Re-exporting and Visibility
+r[vis.reexports]
+
+r[vis.reexports.intro]
Rust allows publicly re-exporting items through a `pub use` directive. Because
this is a public directive, this allows the item to be used in the current
module through the rules above. It essentially allows public access into the
@@ -238,6 +264,7 @@ mod implementation {
This means that any external crate referencing `implementation::api::f` would
receive a privacy violation, while the path `api::f` would be allowed.
+r[vis.reexports.private-item]
When re-exporting a private item, it can be thought of as allowing the "privacy
chain" being short-circuited through the reexport instead of passing through
the namespace hierarchy as it normally would.
diff --git a/src/whitespace.md b/src/whitespace.md
index a93bdcb..cd09994 100644
--- a/src/whitespace.md
+++ b/src/whitespace.md
@@ -1,5 +1,8 @@
# Whitespace
+r[lex.whitespace]
+
+r[lex.whitespace.intro]
Whitespace is any non-empty string containing only characters that have the
[`Pattern_White_Space`] Unicode property, namely:
@@ -15,9 +18,11 @@ Whitespace is any non-empty string containing only characters that have the
- `U+2028` (line separator)
- `U+2029` (paragraph separator)
+r[lex.whitespace.token-sep]
Rust is a "free-form" language, meaning that all forms of whitespace serve only
to separate _tokens_ in the grammar, and have no semantic significance.
+r[lex.whitespace.replacement]
A Rust program has identical meaning if each whitespace element is replaced
with any other legal whitespace element, such as a single space character.
diff --git a/theme/reference.css b/theme/reference.css
index 04b6215..58be918 100644
--- a/theme/reference.css
+++ b/theme/reference.css
@@ -11,46 +11,46 @@ the parenthetical. So for this example, you'd use
}
/*
-Warnings and notes:
+Warnings are defined using admonitions in blockquotes:
-Write the s on their own line. E.g.
+> [!WARNING]
+> This is bad!
-
-
-Warning: This is bad!
-
-
*/
-main .warning p {
- padding: 10px 20px;
- margin: 20px 0;
+main .warning blockquote {
+ padding: 0px;
}
-main .warning p::before {
+main .warning blockquote p {
+ padding: 0px 20px;
+ margin: 10px 0;
+}
+
+main .warning blockquote p:first-child::before {
content: "⚠️ ";
}
-.light main .warning p,
-.rust main .warning p {
+.light main .warning blockquote,
+.rust main .warning blockquote {
border: 2px solid red;
background: #ffcece;
}
-.rust main .warning p {
+.rust main .warning blockquote {
/* overrides previous declaration */
border-color: #961717;
}
-.coal main .warning p,
-.navy main .warning p,
-.ayu main .warning p {
+.coal main .warning blockquote,
+.navy main .warning blockquote,
+.ayu main .warning blockquote {
background: #542626;
}
/* Make the links higher contrast on dark themes */
-.coal main .warning p a,
-.navy main .warning p a,
-.ayu main .warning p a {
+.coal main .warning blockquote p a,
+.navy main .warning blockquote p a,
+.ayu main .warning blockquote p a {
color: #80d0d0;
}
@@ -200,3 +200,33 @@ dfn {
.history > blockquote {
background: #f7c0eb;
}
+
+/* Provides a anchor container for positioning popups. */
+.popup-container {
+ position: relative;
+}
+/* In the test summary page, a convenience class for toggling visibility. */
+.popup-hidden {
+ display: none;
+}
+/* In the test summary page, the styling for the uncovered rule popup. */
+.uncovered-rules-popup {
+ position: absolute;
+ left: -250px;
+ width: 400px;
+ background: var(--bg);
+ border-radius: 4px;
+ border: 1px solid;
+ z-index: 1000;
+ padding: 1rem;
+}
+
+/* The popup that shows when viewing tests for a specific rule. */
+.tests-popup {
+ color: var(--fg);
+ background: var(--bg);
+ border-radius: 4px;
+ border: 1px solid;
+ z-index: 1000;
+ padding: 1rem;
+}
diff --git a/theme/reference.js b/theme/reference.js
new file mode 100644
index 0000000..44a2370
--- /dev/null
+++ b/theme/reference.js
@@ -0,0 +1,24 @@
+/* On the test summary page, toggles the popup for the uncovered tests. */
+function spec_toggle_uncovered(item_index) {
+ let el = document.getElementById(`uncovered-${item_index}`);
+ const currently_hidden = el.classList.contains('popup-hidden');
+ const all = document.querySelectorAll('.uncovered-rules-popup');
+ all.forEach(element => {
+ element.classList.add('popup-hidden');
+ });
+ if (currently_hidden) {
+ el.classList.remove('popup-hidden');
+ }
+}
+
+function spec_toggle_tests(rule_id) {
+ let el = document.getElementById(`tests-${rule_id}`);
+ const currently_hidden = el.classList.contains('popup-hidden');
+ const all = document.querySelectorAll('.tests-popup');
+ all.forEach(element => {
+ element.classList.add('popup-hidden');
+ });
+ if (currently_hidden) {
+ el.classList.remove('popup-hidden');
+ }
+}