Skip to content

Commit cd8bb87

Browse files
authored
Merge branch 'master' into one-line-expressions
2 parents ce87f5f + 3d1ca95 commit cd8bb87

12 files changed

+148
-41
lines changed

book.toml

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ edit-url-template = "https://github.com/rust-lang/reference/edit/master/{path}"
1010

1111
[output.html.redirect]
1212
"/expressions/enum-variant-expr.html" = "struct-expr.html"
13+
"/unsafe-blocks.html" = "unsafe-keyword.html"
14+
"/unsafe-functions.html" = "unsafe-keyword.html"
1315

1416
[rust]
1517
edition = "2021"

src/SUMMARY.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@
118118
- [Inline assembly](inline-assembly.md)
119119

120120
- [Unsafety](unsafety.md)
121-
- [Unsafe functions](unsafe-functions.md)
122-
- [Unsafe blocks](unsafe-blocks.md)
121+
- [The `unsafe` keyword](unsafe-keyword.md)
123122
- [Behavior considered undefined](behavior-considered-undefined.md)
124123
- [Behavior not considered unsafe](behavior-not-considered-unsafe.md)
125124

src/attributes/codegen.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ trait object whose methods are attributed.
347347
[target architecture]: ../conditional-compilation.md#target_arch
348348
[trait]: ../items/traits.md
349349
[undefined behavior]: ../behavior-considered-undefined.md
350-
[unsafe function]: ../unsafe-functions.md
350+
[unsafe function]: ../unsafe-keyword.md
351351
[rust-abi]: ../items/external-blocks.md#abi
352352
[`core::intrinsics::caller_location`]: ../../core/intrinsics/fn.caller_location.html
353353
[`core::panic::Location::caller`]: ../../core/panic/struct.Location.html#method.caller

src/conditional-compilation.md

+19
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,25 @@ Example values:
191191
* `"pc"`
192192
* `"unknown"`
193193

194+
### `target_has_atomic`
195+
196+
Key-value option set for each bit width that the target supports
197+
atomic loads, stores, and compare-and-swap operations.
198+
199+
When this cfg is present, all of the stable [`core::sync::atomic`] APIs are available for
200+
the relevant atomic width.
201+
202+
[`core::sync::atomic`]: ../core/sync/atomic/index.html
203+
204+
Possible values:
205+
206+
* `"8"`
207+
* `"16"`
208+
* `"32"`
209+
* `"64"`
210+
* `"128"`
211+
* `"ptr"`
212+
194213
### `test`
195214

196215
Enabled when compiling the test harness. Done with `rustc` by using the

src/expressions/block-expr.md

+5
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ unsafe {
140140
let a = unsafe { an_unsafe_fn() };
141141
```
142142

143+
## Labelled block expressions
144+
145+
Labelled block expressions are documented in the [Loops and other breakable expressions] section.
146+
143147
## Attributes on block expressions
144148

145149
[Inner attributes] are allowed directly after the opening brace of a block expression in the following situations:
@@ -189,3 +193,4 @@ fn is_unix_platform() -> bool {
189193
[tuple expressions]: tuple-expr.md
190194
[unsafe operations]: ../unsafety.md
191195
[value expressions]: ../expressions.md#place-expressions-and-value-expressions
196+
[Loops and other breakable expressions]: loop-expr.md#labelled-block-expressions

src/expressions/loop-expr.md

+30-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Loops
1+
# Loops and other breakable expressions
22

33
> **<sup>Syntax</sup>**\
44
> _LoopExpression_ :\
@@ -7,23 +7,27 @@
77
> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicateLoopExpression_]\
88
> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicatePatternLoopExpression_]\
99
> &nbsp;&nbsp; &nbsp;&nbsp; | [_IteratorLoopExpression_]\
10+
> &nbsp;&nbsp; &nbsp;&nbsp; | [_LabelBlockExpression_]\
1011
> &nbsp;&nbsp; )
1112
1213
[_LoopLabel_]: #loop-labels
1314
[_InfiniteLoopExpression_]: #infinite-loops
1415
[_PredicateLoopExpression_]: #predicate-loops
1516
[_PredicatePatternLoopExpression_]: #predicate-pattern-loops
1617
[_IteratorLoopExpression_]: #iterator-loops
18+
[_LabelBlockExpression_]: #labelled-block-expressions
1719

18-
Rust supports four loop expressions:
20+
Rust supports five loop expressions:
1921

2022
* A [`loop` expression](#infinite-loops) denotes an infinite loop.
2123
* A [`while` expression](#predicate-loops) loops until a predicate is false.
2224
* A [`while let` expression](#predicate-pattern-loops) tests a pattern.
2325
* A [`for` expression](#iterator-loops) extracts values from an iterator, looping until the iterator is empty.
26+
* A [labelled block expression](#labelled-block-expressions) runs a loop exactly once, but allows exiting the loop early with `break`.
2427

25-
All four types of loop support [`break` expressions](#break-expressions), [`continue` expressions](#continue-expressions), and [labels](#loop-labels).
26-
Only `loop` supports [evaluation to non-trivial values](#break-and-loop-values).
28+
All five types of loop support [`break` expressions](#break-expressions), and [labels](#loop-labels).
29+
All except labelled block expressions support [`continue` expressions](#continue-expressions).
30+
Only `loop` and labelled block expressions support [evaluation to non-trivial values](#break-and-loop-values).
2731

2832
## Infinite loops
2933

@@ -193,6 +197,18 @@ A loop expression may optionally have a _label_. The label is written as a lifet
193197
If a label is present, then labeled `break` and `continue` expressions nested within this loop may exit out of this loop or return control to its head.
194198
See [break expressions](#break-expressions) and [continue expressions](#continue-expressions).
195199

200+
Labels follow the hygiene and shadowing rules of local variables. For example, this code will print "outer loop":
201+
202+
```rust
203+
'a: loop {
204+
'a: loop {
205+
break 'a;
206+
}
207+
print!("outer loop");
208+
break 'a;
209+
}
210+
```
211+
196212
## `break` expressions
197213

198214
> **<sup>Syntax</sup>**\
@@ -226,6 +242,16 @@ Example:
226242

227243
A `break` expression is only permitted in the body of a loop, and has one of the forms `break`, `break 'label` or ([see below](#break-and-loop-values)) `break EXPR` or `break 'label EXPR`.
228244

245+
## Labelled block expressions
246+
247+
> **<sup>Syntax</sup>**\
248+
> _LabelBlockExpression_ :\
249+
> &nbsp;&nbsp; [_BlockExpression_]
250+
251+
Labelled block expressions are exactly like block expressions, except that they allow using `break` expressions within the block.
252+
Unlike other loops, `break` expressions within a label expression *must* have a label (i.e. the label is not optional).
253+
Unlike other loops, labelled block expressions *must* begin with a label.
254+
229255
## `continue` expressions
230256

231257
> **<sup>Syntax</sup>**\

src/items/functions.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ fn answer_to_life_the_universe_and_everything() -> i32 {
5959

6060
## Function parameters
6161

62-
As with `let` bindings, function parameters are irrefutable [patterns], so any
63-
pattern that is valid in a let binding is also valid as a parameter:
62+
Function parameters are irrefutable [patterns], so any pattern that is valid in
63+
an else-less `let` binding is also valid as a parameter:
6464

6565
```rust
6666
fn first((value, _): (i32, i32)) -> i32 { value }

src/statements.md

+29-4
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,35 @@ fn outer() {
4646
> **<sup>Syntax</sup>**\
4747
> _LetStatement_ :\
4848
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_PatternNoTopAlt_]
49-
> ( `:` [_Type_] )<sup>?</sup> (`=` [_Expression_] )<sup>?</sup> `;`
50-
51-
A *`let` statement* introduces a new set of [variables], given by an irrefutable [pattern].
52-
The pattern is followed optionally by a type annotation and then optionally by an initializer expression.
49+
> ( `:` [_Type_] )<sup>?</sup> (`=` [_Expression_] [](#let-else-restriction)
50+
> ( `else` [_BlockExpression_]) <sup>?</sup> ) <sup>?</sup> `;`
51+
>
52+
> <span id="let-else-restriction">† When an `else` block is specified, the
53+
> _Expression_ must not be a [_LazyBooleanExpression_], or end with a `}`.</span>
54+
55+
A *`let` statement* introduces a new set of [variables], given by a [pattern].
56+
The pattern is followed optionally by a type annotation and then either ends,
57+
or is followed by an initializer expression plus an optional `else` block.
5358
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.
5459
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.
5560

61+
If an `else` block is not present, the pattern must be irrefutable.
62+
If an `else` block is present, the pattern may be refutable.
63+
If the pattern does not match (this requires it to be refutable), the `else`
64+
block is executed.
65+
The `else` block must always diverge (evaluate to the [never type]).
66+
67+
```rust
68+
let (mut v, w) = (vec![1, 2, 3], 42); // The bindings may be mut or const
69+
let Some(t) = v.pop() else { // Refutable patterns require an else block
70+
panic!(); // The else block must diverge
71+
};
72+
let [u, v] = [v[0], v[1]] else { // This pattern is irrefutable, so the compiler
73+
// will lint as the else block is redundant.
74+
panic!();
75+
};
76+
```
77+
5678
## Expression statements
5779

5880
> **<sup>Syntax</sup>**\
@@ -106,16 +128,19 @@ The attributes that have meaning on a statement are [`cfg`], and [the lint check
106128
[function]: items/functions.md
107129
[item]: items.md
108130
[module]: items/modules.md
131+
[never type]: types/never.md
109132
[canonical path]: paths.md#canonical-paths
110133
[implementations]: items/implementations.md
111134
[variables]: variables.md
112135
[outer attributes]: attributes.md
113136
[`cfg`]: conditional-compilation.md
114137
[the lint check attributes]: attributes/diagnostics.md#lint-check-attributes
115138
[pattern]: patterns.md
139+
[_BlockExpression_]: expressions/block-expr.md
116140
[_ExpressionStatement_]: #expression-statements
117141
[_Expression_]: expressions.md
118142
[_Item_]: items.md
143+
[_LazyBooleanExpression_]: expressions/operator-expr.md#lazy-boolean-operators
119144
[_LetStatement_]: #let-statements
120145
[_MacroInvocationSemi_]: macros.md#macro-invocation
121146
[_OuterAttribute_]: attributes.md

src/types/function-pointer.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,5 @@ restrictions as [regular function parameters].
6262
[closures]: closure.md
6363
[extern function]: ../items/functions.md#extern-function-qualifier
6464
[function items]: function-item.md
65-
[unsafe function]: ../unsafe-functions.md
65+
[unsafe function]: ../unsafe-keyword.md
6666
[regular function parameters]: ../items/functions.md#attributes-on-function-parameters

src/unsafe-blocks.md

-22
This file was deleted.

src/unsafe-functions.md

-5
This file was deleted.

src/unsafe-keyword.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# The `unsafe` keyword
2+
3+
The `unsafe` keyword can occur in several different contexts:
4+
unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), and unsafe trait implementations (`unsafe impl`).
5+
It plays several different roles, depending on where it is used and whether the `unsafe_op_in_unsafe_fn` lint is enabled:
6+
- it is used to mark code that *defines* extra safety conditions (`unsafe fn`, `unsafe trait`)
7+
- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`])
8+
9+
The following discusses each of these cases.
10+
See the [keyword documentation][keyword] for some illustrative examples.
11+
12+
## Unsafe functions (`unsafe fn`)
13+
14+
Unsafe functions are functions that are not safe in all contexts and/or for all possible inputs.
15+
We say they have *extra safety conditions*, which are requirements that must be upheld by all callers and that the compiler does not check.
16+
For example, [`get_unchecked`] has the extra safety condition that the index must be in-bounds.
17+
The unsafe function should come with documentation explaining what those extra safety conditions are.
18+
19+
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.
20+
21+
## Unsafe blocks (`unsafe {}`)
22+
23+
A block of code can be prefixed with the `unsafe` keyword, to permit calling `unsafe` functions or dereferencing raw pointers.
24+
By default, the body of an unsafe function is also considered to be an unsafe block;
25+
this can be changed by enabling the [`unsafe_op_in_unsafe_fn`] lint.
26+
27+
By putting operations into an unsafe block, the programmer states that they have taken care of satisfying the extra safety conditions of all operations inside that block.
28+
29+
Unsafe blocks are the logical dual to unsafe functions:
30+
where unsafe functions define a proof obligation that callers must uphold, unsafe blocks state that all relevant proof obligations have been discharged.
31+
There are many ways to discharge proof obligations;
32+
for example, there could be run-time checks or data structure invariants that guarantee that certain properties are definitely true, or the unsafe block could be inside an `unsafe fn` and use its own proof obligations to discharge the proof obligations of its callees.
33+
34+
Unsafe blocks are used to wrap foreign libraries, make direct use of hardware or implement features not directly present in the language.
35+
For example, Rust provides the language features necessary to implement memory-safe concurrency in the language but the implementation of threads and message passing in the standard library uses unsafe blocks.
36+
37+
Rust's type system is a conservative approximation of the dynamic safety requirements, so in some cases there is a performance cost to using safe code.
38+
For example, a doubly-linked list is not a tree structure and can only be represented with reference-counted pointers in safe code.
39+
By using `unsafe` blocks to represent the reverse links as raw pointers, it can be implemented without reference counting.
40+
(See ["Learn Rust With Entirely Too Many Linked Lists"](https://rust-unofficial.github.io/too-many-lists/) for a more in-depth exploration of this particular example.)
41+
42+
## Unsafe traits (`unsafe trait`)
43+
44+
An unsafe trait is a trait that comes with extra safety conditions that must be upheld by *implementations* of the trait.
45+
The unsafe trait should come with documentation explaining what those extra safety conditions are.
46+
47+
Such a trait must be prefixed with the keyword `unsafe` and can only be implemented by `unsafe impl` blocks.
48+
49+
## Unsafe trait implementations (`unsafe impl`)
50+
51+
When implementing an unsafe trait, the implementation needs to be prefixed with the `unsafe` keyword.
52+
By writing `unsafe impl`, the programmer states that they have taken care of satisfying the extra safety conditions required by the trait.
53+
54+
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.
55+
56+
[keyword]: ../std/keyword.unsafe.html
57+
[`get_unchecked`]: ../std/primitive.slice.html#method.get_unchecked
58+
[`unsafe_op_in_unsafe_fn`]: ../rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn

0 commit comments

Comments
 (0)