Skip to content

Commit 0e9a7a6

Browse files
Merge branch 'master' into subtyping-rewrite
2 parents 9fb3a36 + 3a43983 commit 0e9a7a6

24 files changed

+409
-107
lines changed

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ jobs:
66
name: Test
77
runs-on: ubuntu-latest
88
steps:
9-
- uses: actions/checkout@v2
9+
- uses: actions/checkout@v3
1010
- name: Update rustup
1111
run: rustup self update
1212
- name: Install Rust

src/borrow-splitting.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Splitting Borrows
22

33
The mutual exclusion property of mutable references can be very limiting when
4-
working with a composite structure. The borrow checker understands some basic
5-
stuff, but will fall over pretty easily. It does understand structs
6-
sufficiently to know that it's possible to borrow disjoint fields of a struct
7-
simultaneously. So this works today:
4+
working with a composite structure. The borrow checker (a.k.a. borrowck)
5+
understands some basic stuff, but will fall over pretty easily. It does
6+
understand structs sufficiently to know that it's possible to borrow disjoint
7+
fields of a struct simultaneously. So this works today:
88

99
```rust
1010
struct Foo {

src/checked-uninit.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ fn main() {
1818
```
1919

2020
This is based off of a basic branch analysis: every branch must assign a value
21-
to `x` before it is first used. Interestingly, Rust doesn't require the variable
21+
to `x` before it is first used. For short, we also say that "`x` is init" or
22+
"`x` is uninit".
23+
24+
Interestingly, Rust doesn't require the variable
2225
to be mutable to perform a delayed initialization if every branch assigns
2326
exactly once. However the analysis does not take advantage of constant analysis
2427
or anything like that. So this compiles:

src/destructors.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Next variant.
120120

121121
In general this works really nicely because you don't need to worry about
122122
adding/removing drops when you refactor your data layout. Still there's
123-
certainly many valid usecases for needing to do trickier things with
123+
certainly many valid use cases for needing to do trickier things with
124124
destructors.
125125

126126
The classic safe solution to overriding recursive drop and allowing moving out

src/dropck.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ Interestingly, only generic types need to worry about this. If they aren't
121121
generic, then the only lifetimes they can harbor are `'static`, which will truly
122122
live _forever_. This is why this problem is referred to as _sound generic drop_.
123123
Sound generic drop is enforced by the _drop checker_. As of this writing, some
124-
of the finer details of how the drop checker validates types is totally up in
125-
the air. However The Big Rule is the subtlety that we have focused on this whole
126-
section:
124+
of the finer details of how the drop checker (also called dropck) validates
125+
types is totally up in the air. However The Big Rule is the subtlety that we
126+
have focused on this whole section:
127127

128128
**For a generic type to soundly implement drop, its generics arguments must
129129
strictly outlive it.**

src/exception-safety.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ The basic idea is simple: if the comparison panics, we just toss the loose
140140
element in the logically uninitialized index and bail out. Anyone who observes
141141
the heap will see a potentially *inconsistent* heap, but at least it won't
142142
cause any double-drops! If the algorithm terminates normally, then this
143-
operation happens to coincide precisely with the how we finish up regardless.
143+
operation happens to coincide precisely with how we finish up regardless.
144144

145145
Sadly, Rust has no such construct, so we're going to need to roll our own! The
146146
way to do this is to store the algorithm's state in a separate struct with a

src/exotic-sizes.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ In principle, Rust can do some interesting analyses and optimizations based
135135
on this fact. For instance, `Result<T, Void>` is represented as just `T`,
136136
because the `Err` case doesn't actually exist (strictly speaking, this is only
137137
an optimization that is not guaranteed, so for example transmuting one into the
138-
other is still UB).
138+
other is still Undefined Behavior).
139139

140140
The following *could* also compile:
141141

@@ -157,15 +157,15 @@ because that wouldn't make sense.
157157
We recommend against modelling C's `void*` type with `*const Void`.
158158
A lot of people started doing that but quickly ran into trouble because
159159
Rust doesn't really have any safety guards against trying to instantiate
160-
empty types with unsafe code, and if you do it, it's Undefined Behaviour.
160+
empty types with unsafe code, and if you do it, it's Undefined Behavior.
161161
This was especially problematic because developers had a habit of converting
162-
raw pointers to references and `&Void` is *also* Undefined Behaviour to
162+
raw pointers to references and `&Void` is *also* Undefined Behavior to
163163
construct.
164164

165165
`*const ()` (or equivalent) works reasonably well for `void*`, and can be made
166166
into a reference without any safety problems. It still doesn't prevent you from
167167
trying to read or write values, but at least it compiles to a no-op instead
168-
of UB.
168+
of Undefined Behavior.
169169

170170
## Extern Types
171171

src/ffi.md

+109-6
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ We'll create a C file to call the `hello_from_rust` function and compile it by `
281281
C file should look like:
282282

283283
```c
284+
extern void hello_from_rust();
285+
284286
int main(void) {
285287
hello_from_rust();
286288
return 0;
@@ -716,17 +718,118 @@ void register(int (*f)(int (*)(int), int)) {
716718
717719
No `transmute` required!
718720
719-
## FFI and panics
721+
## FFI and unwinding
722+
723+
It’s important to be mindful of unwinding when working with FFI. Each
724+
non-`Rust` ABI comes in two variants, one with `-unwind` suffix and one without. If
725+
you expect Rust `panic`s or foreign (e.g. C++) exceptions to cross an FFI
726+
boundary, that boundary must use the appropriate `-unwind` ABI string (note
727+
that compiling with `panic=abort` will still cause `panic!` to immediately
728+
abort the process, regardless of which ABI is specified by the function that
729+
`panic`s).
730+
731+
Conversely, if you do not expect unwinding to cross an ABI boundary, use one of
732+
the non-`unwind` ABI strings (other than `Rust`, which always permits
733+
unwinding). If an unwinding operation does encounter an ABI boundary that is
734+
not permitted to unwind, the behavior depends on the source of the unwinding
735+
(Rust `panic` or a foreign exception):
736+
737+
* `panic` will cause the process to safely abort.
738+
* A foreign exception entering Rust will cause undefined behavior.
739+
740+
Note that the interaction of `catch_unwind` with foreign exceptions **is
741+
undefined**, as is the interaction of `panic` with foreign exception-catching
742+
mechanisms (notably C++'s `try`/`catch`).
743+
744+
### Rust `panic` with `"C-unwind"`
745+
746+
<!-- ignore: using unstable feature -->
747+
```rust,ignore
748+
#[no_mangle]
749+
extern "C-unwind" fn example() {
750+
panic!("Uh oh");
751+
}
752+
```
753+
754+
This function (when compiled with `panic=unwind`) is permitted to unwind C++
755+
stack frames.
756+
757+
```text
758+
[Rust function with `catch_unwind`, which stops the unwinding]
759+
|
760+
...
761+
|
762+
[C++ frames]
763+
| ^
764+
| (calls) | (unwinding
765+
v | goes this
766+
[Rust function `example`] | way)
767+
| |
768+
+--- rust function panics --+
769+
```
770+
771+
If the C++ frames have objects, their destructors will be called.
772+
773+
### C++ `throw` with `"C-unwind"`
774+
775+
<!-- ignore: using unstable feature -->
776+
```rust,ignore
777+
#[link(...)]
778+
extern "C-unwind" {
779+
// A C++ function that may throw an exception
780+
fn may_throw();
781+
}
782+
783+
#[no_mangle]
784+
extern "C-unwind" fn rust_passthrough() {
785+
let b = Box::new(5);
786+
unsafe { may_throw(); }
787+
println!("{:?}", &b);
788+
}
789+
```
790+
791+
A C++ function with a `try` block may invoke `rust_passthrough` and `catch` an
792+
exception thrown by `may_throw`.
793+
794+
```text
795+
[C++ function with `try` block that invokes `rust_passthrough`]
796+
|
797+
...
798+
|
799+
[Rust function `rust_passthrough`]
800+
| ^
801+
| (calls) | (unwinding
802+
v | goes this
803+
[C++ function `may_throw`] | way)
804+
| |
805+
+--- C++ function throws ----+
806+
```
807+
808+
If `may_throw` does throw an exception, `b` will be dropped. Otherwise, `5`
809+
will be printed.
810+
811+
### `panic` can be stopped at an ABI boundary
812+
813+
```rust
814+
#[no_mangle]
815+
extern "C" fn assert_nonzero(input: u32) {
816+
assert!(input != 0)
817+
}
818+
```
819+
820+
If `assert_nonzero` is called with the argument `0`, the runtime is guaranteed
821+
to (safely) abort the process, whether or not compiled with `panic=abort`.
822+
823+
### Catching `panic` preemptively
720824

721-
It’s important to be mindful of `panic!`s when working with FFI. A `panic!`
722-
across an FFI boundary is undefined behavior. If you’re writing code that may
723-
panic, you should run it in a closure with [`catch_unwind`]:
825+
If you are writing Rust code that may panic, and you don't wish to abort the
826+
process if it panics, you must use [`catch_unwind`]:
724827

725828
```rust
726829
use std::panic::catch_unwind;
727830

728831
#[no_mangle]
729-
pub extern fn oh_no() -> i32 {
832+
pub extern "C" fn oh_no() -> i32 {
730833
let result = catch_unwind(|| {
731834
panic!("Oops!");
732835
});
@@ -740,7 +843,7 @@ fn main() {}
740843
```
741844

742845
Please note that [`catch_unwind`] will only catch unwinding panics, not
743-
those who abort the process. See the documentation of [`catch_unwind`]
846+
those that abort the process. See the documentation of [`catch_unwind`]
744847
for more information.
745848

746849
[`catch_unwind`]: ../std/panic/fn.catch_unwind.html

src/intro.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Where The Reference exists to detail the syntax and semantics of every part of t
3232

3333
The Reference will tell you the syntax and semantics of references, destructors, and unwinding, but it won't tell you how combining them can lead to exception-safety issues, or how to deal with those issues.
3434

35-
It should be noted that we haven't synced The Rustnomicon and The Reference well, so they may have a duplicate content.
35+
It should be noted that we haven't synced The Rustnomicon and The Reference well, so they may have duplicate content.
3636
In general, if the two documents disagree, The Reference should be assumed to be correct (it isn't yet considered normative, it's just better maintained).
3737

3838
Topics that are within the scope of this book include: the meaning of (un)safety, unsafe primitives provided by the language and standard library, techniques for creating safe abstractions with those unsafe primitives, subtyping and variance, exception-safety (panic/unwind-safety), working with uninitialized memory, type punning, concurrency, interoperating with other languages (FFI), optimization tricks, how constructs lower to compiler/OS/hardware primitives, how to **not** make the memory model people angry, how you're **going** to make the memory model people angry, and more.

src/leaking.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ horribly degenerate. Also *oh my gosh* it's such a ridiculous corner case.
179179
> Note: This API has already been removed from std, for more information
180180
> you may refer [issue #24292](https://github.com/rust-lang/rust/issues/24292).
181181
>
182-
> We still remain this chapter here because we think this example is still
183-
> important, regardless of if it is still in std.
182+
> This section remains here because we think this example is still
183+
> important, regardless of whether it is part of std or not.
184184
185185
The thread::scoped API intended to allow threads to be spawned that reference
186186
data on their parent's stack without any synchronization over that data by

src/lifetime-mismatch.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@ care about, but the lifetime system is too coarse-grained to handle that.
7373

7474
## Improperly reduced borrows
7575

76-
The following code fails to compile, because Rust doesn't understand that the borrow
77-
is no longer needed and conservatively falls back to using a whole scope for it.
78-
This will eventually get fixed.
76+
The following code fails to compile, because Rust sees that a variable, `map`,
77+
is borrowed twice, and can not infer that the first borrow stops to be needed
78+
before the second one occurs. This is caused by Rust conservatively falling back
79+
to using a whole scope for the first borow. This will eventually get fixed.
7980

8081
```rust,compile_fail
8182
# use std::collections::HashMap;

src/lifetimes.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ z = y;
8080
'b: {
8181
let z: &'b i32;
8282
'c: {
83-
// Must use 'b here because this reference is
84-
// being passed to that scope.
83+
// Must use 'b here because the reference to x is
84+
// being passed to the scope 'b.
8585
let y: &'b i32 = &'b x;
8686
z = y;
8787
}
@@ -208,11 +208,12 @@ violate the *second* rule of references.
208208

209209
However this is *not at all* how Rust reasons that this program is bad. Rust
210210
doesn't understand that `x` is a reference to a subpath of `data`. It doesn't
211-
understand `Vec` at all. What it *does* see is that `x` has to live for `'b` to
212-
be printed. The signature of `Index::index` subsequently demands that the
213-
reference we take to `data` has to survive for `'b`. When we try to call `push`,
214-
it then sees us try to make an `&'c mut data`. Rust knows that `'c` is contained
215-
within `'b`, and rejects our program because the `&'b data` must still be alive!
211+
understand `Vec` at all. What it *does* see is that `x` has to live for `'b` in
212+
order to be printed. The signature of `Index::index` subsequently demands that
213+
the reference we take to `data` has to survive for `'b`. When we try to call
214+
`push`, it then sees us try to make an `&'c mut data`. Rust knows that `'c` is
215+
contained within `'b`, and rejects our program because the `&'b data` must still
216+
be alive!
216217

217218
Here we see that the lifetime system is much more coarse than the reference
218219
semantics we're actually interested in preserving. For the most part, *that's

src/meet-safe-and-unsafe.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ do, but we'll do anyway.
4141
Safe Rust is the *true* Rust programming language. If all you do is write Safe
4242
Rust, you will never have to worry about type-safety or memory-safety. You will
4343
never endure a dangling pointer, a use-after-free, or any other kind of
44-
Undefined Behavior.
44+
Undefined Behavior (a.k.a. UB).
4545

4646
The standard library also gives you enough utilities out of the box that you'll
4747
be able to write high-performance applications and libraries in pure idiomatic

0 commit comments

Comments
 (0)