Skip to content

Commit 0d116cf

Browse files
authored
Merge branch 'master' into handle-drop-zst
2 parents 94951ed + b4448fa commit 0d116cf

File tree

12 files changed

+69
-97
lines changed

12 files changed

+69
-97
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
merge_group:
55

66
env:
7-
MDBOOK_VERSION: 0.4.40
7+
MDBOOK_VERSION: 0.4.45
88

99
jobs:
1010
test:

book.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ git-repository-url = "https://github.com/rust-lang/nomicon"
3232
"./arc.html" = "./arc-mutex/arc.html"
3333

3434
[rust]
35-
edition = "2021"
35+
edition = "2024"

src/arc-mutex/arc-drop.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ implementation of `Arc`][3]:
5151
> > "acquire" operation before deleting the object.
5252
>
5353
> In particular, while the contents of an Arc are usually immutable, it's
54-
> possible to have interior writes to something like a Mutex<T>. Since a Mutex
54+
> possible to have interior writes to something like a `Mutex<T>`. Since a Mutex
5555
> is not acquired when it is deleted, we can't rely on its synchronization logic
5656
> to make writes in thread A visible to a destructor running in thread B.
5757
>

src/beneath-std.md

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -30,46 +30,10 @@ We will probably need a nightly version of the compiler to produce
3030
a `#![no_std]` executable because on many platforms, we have to provide the
3131
`eh_personality` [lang item], which is unstable.
3232

33-
Controlling the entry point is possible in two ways: the `#[start]` attribute,
34-
or overriding the default shim for the C `main` function with your own.
35-
Additionally, it's required to define a [panic handler function](panic-handler.html).
36-
37-
The function marked `#[start]` is passed the command line parameters
38-
in the same format as C (aside from the exact integer types being used):
39-
40-
```rust
41-
#![feature(start, lang_items, core_intrinsics, rustc_private)]
42-
#![allow(internal_features)]
43-
#![no_std]
33+
You will need to define a symbol for the entry point that is suitable for your target. For example, `main`, `_start`, `WinMain`, or whatever starting point is relevant for your target.
34+
Additionally, you need to use the `#![no_main]` attribute to prevent the compiler from attempting to generate an entry point itself.
4435

45-
// Necessary for `panic = "unwind"` builds on cfg(unix) platforms.
46-
#![feature(panic_unwind)]
47-
extern crate unwind;
48-
49-
// Pull in the system libc library for what crt0.o likely requires.
50-
#[cfg(not(windows))]
51-
extern crate libc;
52-
53-
use core::panic::PanicInfo;
54-
55-
// Entry point for this program.
56-
#[start]
57-
fn main(_argc: isize, _argv: *const *const u8) -> isize {
58-
0
59-
}
60-
61-
// These functions are used by the compiler, but not for an empty program like this.
62-
// They are normally provided by `std`.
63-
#[lang = "eh_personality"]
64-
fn rust_eh_personality() {}
65-
#[panic_handler]
66-
fn panic_handler(_info: &PanicInfo) -> ! { core::intrinsics::abort() }
67-
```
68-
69-
To override the compiler-inserted `main` shim, we have to disable it
70-
with `#![no_main]` and then create the appropriate symbol with the
71-
correct ABI and the correct name, which requires overriding the
72-
compiler's name mangling too:
36+
Additionally, it's required to define a [panic handler function](panic-handler.html).
7337

7438
```rust
7539
#![feature(lang_items, core_intrinsics, rustc_private)]
@@ -89,7 +53,7 @@ use core::ffi::{c_char, c_int};
8953
use core::panic::PanicInfo;
9054

9155
// Entry point for this program.
92-
#[no_mangle] // ensure that this symbol is included in the output as `main`
56+
#[unsafe(no_mangle)] // ensure that this symbol is included in the output as `main`
9357
extern "C" fn main(_argc: c_int, _argv: *const *const c_char) -> c_int {
9458
0
9559
}

src/exotic-sizes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This isn't always the case in Rust.
88
Rust supports Dynamically Sized Types (DSTs): types without a statically
99
known size or alignment. On the surface, this is a bit nonsensical: Rust *must*
1010
know the size and alignment of something in order to correctly work with it! In
11-
this regard, DSTs are not normal types. Because they lack a statically known
11+
this regard, DSTs are not normal types. Since they lack a statically known
1212
size, these types can only exist behind a pointer. Any pointer to a
1313
DST consequently becomes a *wide* pointer consisting of the pointer and the
1414
information that "completes" them (more on this below).
@@ -40,7 +40,7 @@ struct MySuperSlice {
4040
}
4141
```
4242

43-
Although such a type is largely useless without a way to construct it. Currently the
43+
Unfortunately, such a type is largely useless without a way to construct it. Currently the
4444
only properly supported way to create a custom DST is by making your type generic
4545
and performing an *unsizing coercion*:
4646

src/ffi.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ compile if snappy is installed:
3131
use libc::size_t;
3232
3333
#[link(name = "snappy")]
34-
extern {
34+
unsafe extern "C" {
3535
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
3636
}
3737
@@ -64,7 +64,7 @@ The `extern` block can be extended to cover the entire snappy API:
6464
use libc::{c_int, size_t};
6565
6666
#[link(name = "snappy")]
67-
extern {
67+
unsafe extern {
6868
fn snappy_compress(input: *const u8,
6969
input_length: size_t,
7070
compressed: *mut u8,
@@ -251,7 +251,7 @@ First, we assume you have a lib crate named as `rust_from_c`.
251251
`lib.rs` should have Rust code as following:
252252

253253
```rust
254-
#[no_mangle]
254+
#[unsafe(no_mangle)]
255255
pub extern "C" fn hello_from_rust() {
256256
println!("Hello from Rust!");
257257
}
@@ -331,7 +331,7 @@ extern fn callback(a: i32) {
331331
}
332332
333333
#[link(name = "extlib")]
334-
extern {
334+
unsafe extern {
335335
fn register_callback(cb: extern fn(i32)) -> i32;
336336
fn trigger_callback();
337337
}
@@ -383,7 +383,7 @@ struct RustObject {
383383
// Other members...
384384
}
385385
386-
extern "C" fn callback(target: *mut RustObject, a: i32) {
386+
unsafe extern "C" fn callback(target: *mut RustObject, a: i32) {
387387
println!("I'm called from C with value {0}", a);
388388
unsafe {
389389
// Update the value in RustObject with the value received from the callback:
@@ -392,9 +392,9 @@ extern "C" fn callback(target: *mut RustObject, a: i32) {
392392
}
393393
394394
#[link(name = "extlib")]
395-
extern {
395+
unsafe extern {
396396
fn register_callback(target: *mut RustObject,
397-
cb: extern fn(*mut RustObject, i32)) -> i32;
397+
cb: unsafe extern fn(*mut RustObject, i32)) -> i32;
398398
fn trigger_callback();
399399
}
400400
@@ -523,7 +523,7 @@ blocks with the `static` keyword:
523523
<!-- ignore: requires libc crate -->
524524
```rust,ignore
525525
#[link(name = "readline")]
526-
extern {
526+
unsafe extern {
527527
static rl_readline_version: libc::c_int;
528528
}
529529
@@ -543,7 +543,7 @@ use std::ffi::CString;
543543
use std::ptr;
544544
545545
#[link(name = "readline")]
546-
extern {
546+
unsafe extern {
547547
static mut rl_prompt: *const libc::c_char;
548548
}
549549
@@ -573,7 +573,7 @@ conventions. Rust provides a way to tell the compiler which convention to use:
573573
#[cfg(all(target_os = "win32", target_arch = "x86"))]
574574
#[link(name = "kernel32")]
575575
#[allow(non_snake_case)]
576-
extern "stdcall" {
576+
unsafe extern "stdcall" {
577577
fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int;
578578
}
579579
# fn main() { }
@@ -635,7 +635,7 @@ In C, functions can be 'variadic', meaning they accept a variable number of argu
635635
be achieved in Rust by specifying `...` within the argument list of a foreign function declaration:
636636

637637
```no_run
638-
extern {
638+
unsafe extern {
639639
fn foo(x: i32, ...);
640640
}
641641
@@ -685,7 +685,7 @@ we have function pointers flying across the FFI boundary in both directions.
685685
use libc::c_int;
686686
687687
# #[cfg(hidden)]
688-
extern "C" {
688+
unsafe extern "C" {
689689
/// Registers the callback.
690690
fn register(cb: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>, c_int) -> c_int>);
691691
}
@@ -750,8 +750,8 @@ mechanisms (notably C++'s `try`/`catch`).
750750
751751
<!-- ignore: using unstable feature -->
752752
```rust,ignore
753-
#[no_mangle]
754-
extern "C-unwind" fn example() {
753+
#[unsafe(no_mangle)]
754+
unsafe extern "C-unwind" fn example() {
755755
panic!("Uh oh");
756756
}
757757
```
@@ -780,13 +780,13 @@ If the C++ frames have objects, their destructors will be called.
780780
<!-- ignore: using unstable feature -->
781781
```rust,ignore
782782
#[link(...)]
783-
extern "C-unwind" {
783+
unsafe extern "C-unwind" {
784784
// A C++ function that may throw an exception
785785
fn may_throw();
786786
}
787787
788-
#[no_mangle]
789-
extern "C-unwind" fn rust_passthrough() {
788+
#[unsafe(no_mangle)]
789+
unsafe extern "C-unwind" fn rust_passthrough() {
790790
let b = Box::new(5);
791791
unsafe { may_throw(); }
792792
println!("{:?}", &b);
@@ -816,7 +816,7 @@ will be printed.
816816
### `panic` can be stopped at an ABI boundary
817817

818818
```rust
819-
#[no_mangle]
819+
#[unsafe(no_mangle)]
820820
extern "C" fn assert_nonzero(input: u32) {
821821
assert!(input != 0)
822822
}
@@ -833,7 +833,7 @@ process if it panics, you must use [`catch_unwind`]:
833833
```rust
834834
use std::panic::catch_unwind;
835835

836-
#[no_mangle]
836+
#[unsafe(no_mangle)]
837837
pub extern "C" fn oh_no() -> i32 {
838838
let result = catch_unwind(|| {
839839
panic!("Oops!");
@@ -867,7 +867,7 @@ We can represent this in Rust with the `c_void` type:
867867
868868
<!-- ignore: requires libc crate -->
869869
```rust,ignore
870-
extern "C" {
870+
unsafe extern "C" {
871871
pub fn foo(arg: *mut libc::c_void);
872872
pub fn bar(arg: *mut libc::c_void);
873873
}
@@ -891,18 +891,18 @@ To do this in Rust, let’s create our own opaque types:
891891
```rust
892892
#[repr(C)]
893893
pub struct Foo {
894-
_data: [u8; 0],
894+
_data: (),
895895
_marker:
896896
core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
897897
}
898898
#[repr(C)]
899899
pub struct Bar {
900-
_data: [u8; 0],
900+
_data: (),
901901
_marker:
902902
core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
903903
}
904904
905-
extern "C" {
905+
unsafe extern "C" {
906906
pub fn foo(arg: *mut Foo);
907907
pub fn bar(arg: *mut Bar);
908908
}

src/intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Topics that are within the scope of this book include: the meaning of (un)safety
3939

4040
The Rustonomicon is not a place to exhaustively describe the semantics and guarantees of every single API in the standard library, nor is it a place to exhaustively describe every feature of Rust.
4141

42-
Unless otherwise noted, Rust code in this book uses the Rust 2021 edition.
42+
Unless otherwise noted, Rust code in this book uses the Rust 2024 edition.
4343

4444
[trpl]: ../book/index.html
4545
[ref]: ../reference/index.html

src/other-reprs.md

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ There's also the [unsafe code guidelines] (note that it's **NOT** normative).
77

88
This is the most important `repr`. It has fairly simple intent: do what C does.
99
The order, size, and alignment of fields is exactly what you would expect from C
10-
or C++. Any type you expect to pass through an FFI boundary should have
10+
or C++. The type is also passed across `extern "C"` function call boundaries the
11+
same way C would pass the corresponding type. Any type you expect to pass through an FFI boundary should have
1112
`repr(C)`, as C is the lingua-franca of the programming world. This is also
1213
necessary to soundly do more elaborate tricks with data layout such as
1314
reinterpreting values as a different type.
@@ -86,10 +87,14 @@ be 0. However Rust will not allow you to create an enum where two variants have
8687
the same discriminant.
8788

8889
The term "fieldless enum" only means that the enum doesn't have data in any
89-
of its variants. A fieldless enum without a `repr(u*)` or `repr(C)` is
90-
still a Rust native type, and does not have a stable ABI representation.
91-
Adding a `repr` causes it to be treated exactly like the specified
92-
integer type for ABI purposes.
90+
of its variants. A fieldless enum without a `repr` is
91+
still a Rust native type, and does not have a stable layout or representation.
92+
Adding a `repr(u*)`/`repr(i*)` causes it to be treated exactly like the specified
93+
integer type for layout purposes (except that the compiler will still exploit its
94+
knowledge of "invalid" values at this type to optimize enum layout, such as when
95+
this enum is wrapped in `Option`). Note that the function call ABI for these
96+
types is still in general unspecified, except that across `extern "C"` calls they
97+
are ABI-compatible with C enums of the same sign and size.
9398

9499
If the enum has fields, the effect is similar to the effect of `repr(C)`
95100
in that there is a defined layout of the type. This makes it possible to
@@ -119,31 +124,34 @@ assert_eq!(16, size_of::<MyReprOption<&u16>>());
119124

120125
This optimization still applies to fieldless enums with an explicit `repr(u*)`, `repr(i*)`, or `repr(C)`.
121126

122-
## repr(packed)
127+
## repr(packed), repr(packed(n))
123128

124-
`repr(packed)` forces Rust to strip any padding, and only align the type to a
125-
byte. This may improve the memory footprint, but will likely have other negative
126-
side-effects.
129+
`repr(packed(n))` (where `n` is a power of two) forces the type to have an
130+
alignment of *at most* `n`. Most commonly used without an explicit `n`,
131+
`repr(packed)` is equivalent to `repr(packed(1))` which forces Rust to strip
132+
any padding, and only align the type to a byte. This may improve the memory
133+
footprint, but will likely have other negative side-effects.
127134

128-
In particular, most architectures *strongly* prefer values to be aligned. This
129-
may mean the unaligned loads are penalized (x86), or even fault (some ARM
130-
chips). For simple cases like directly loading or storing a packed field, the
131-
compiler might be able to paper over alignment issues with shifts and masks.
132-
However if you take a reference to a packed field, it's unlikely that the
133-
compiler will be able to emit code to avoid an unaligned load.
135+
In particular, most architectures *strongly* prefer values to be naturally
136+
aligned. This may mean that unaligned loads are penalized (x86), or even fault
137+
(some ARM chips). For simple cases like directly loading or storing a packed
138+
field, the compiler might be able to paper over alignment issues with shifts
139+
and masks. However if you take a reference to a packed field, it's unlikely
140+
that the compiler will be able to emit code to avoid an unaligned load.
134141

135142
[As this can cause undefined behavior][ub loads], the lint has been implemented
136143
and it will become a hard error.
137144

138-
`repr(packed)` is not to be used lightly. Unless you have extreme requirements,
139-
this should not be used.
145+
`repr(packed)/repr(packed(n))` is not to be used lightly. Unless you have
146+
extreme requirements, this should not be used.
140147

141-
This repr is a modifier on `repr(C)` and `repr(Rust)`.
148+
This repr is a modifier on `repr(C)` and `repr(Rust)`. For FFI compatibility
149+
you most likely always want to be explicit: `repr(C, packed)`.
142150

143151
## repr(align(n))
144152

145153
`repr(align(n))` (where `n` is a power of two) forces the type to have an
146-
alignment of *at least* n.
154+
alignment of *at least* `n`.
147155

148156
This enables several tricks, like making sure neighboring elements of an array
149157
never share the same cache line with each other (which may speed up certain

src/races.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ thread::spawn(move || {
6060
println!("{}", data[idx.load(Ordering::SeqCst)]);
6161
```
6262

63-
We can cause a data race if we instead do the bound check in advance, and then
64-
unsafely access the data with an unchecked value:
63+
We can cause a race condition to violate memory safety if we instead do the bound
64+
check in advance, and then unsafely access the data with an unchecked value:
6565

6666
```rust,no_run
6767
use std::thread;

src/references.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# References
22

3-
There are two kinds of reference:
3+
There are two kinds of references:
44

55
* Shared reference: `&`
66
* Mutable reference: `&mut`

0 commit comments

Comments
 (0)