Skip to content

Commit a5b09d3

Browse files
committedMar 31, 2020
Auto merge of #70625 - Dylan-DPC:rollup-o8n2hw8, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #69425 (add fn make_contiguous to VecDeque) - #69458 (improve folder name for persistent doc tests) - #70268 (Document ThreadSanitizer in unstable-book) - #70600 (Ensure there are versions of test code for aarch64 windows) - #70606 (Clean up E0466 explanation) - #70614 (remove unnecessary relocation check in const_prop) - #70623 (Fix broken link in README) Failed merges: r? @ghost
2 parents 75ff311 + 011c090 commit a5b09d3

File tree

9 files changed

+454
-205
lines changed

9 files changed

+454
-205
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ Also, you may find the [rustdocs for the compiler itself][rustdocs] useful.
256256
257257
[rust-discord]: https://discord.gg/rust-lang
258258
[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/about-this-guide.html
259-
[rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/
259+
[rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/
260260
261261
## License
262262

‎src/doc/unstable-book/src/compiler-flags/sanitizer.md

+150-86
Original file line numberDiff line numberDiff line change
@@ -6,73 +6,78 @@ The tracking issue for this feature is: [#39699](https://github.com/rust-lang/ru
66

77
This feature allows for use of one of following sanitizers:
88

9-
* [AddressSanitizer][clang-asan] a faster memory error detector. Can
10-
detect out-of-bounds access to heap, stack, and globals, use after free, use
11-
after return, double free, invalid free, memory leaks.
9+
* [AddressSanitizer][clang-asan] a fast memory error detector.
1210
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
1311
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
1412
* [ThreadSanitizer][clang-tsan] a fast data race detector.
1513

16-
To enable a sanitizer compile with `-Zsanitizer=...` option, where value is one
17-
of `address`, `leak`, `memory` or `thread`.
14+
To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
15+
`-Zsanitizer=memory` or `-Zsanitizer=thread`. Only a single sanitizer can be
16+
enabled at a time.
1817

19-
# Examples
18+
# AddressSanitizer
2019

21-
This sections show various issues that can be detected with sanitizers. For
22-
simplicity, the examples are prepared under assumption that optimization level
23-
used is zero.
20+
AddressSanitizer is a memory error detector. It can detect the following types
21+
of bugs:
2422

25-
## AddressSanitizer
23+
* Out of bound accesses to heap, stack and globals
24+
* Use after free
25+
* Use after return (runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1`)
26+
* Use after scope
27+
* Double-free, invalid free
28+
* Memory leaks
29+
30+
AddressSanitizer is supported on the following targets:
31+
32+
* `x86_64-apple-darwin`
33+
* `x86_64-unknown-linux-gnu`
34+
35+
AddressSanitizer works with non-instrumented code although it will impede its
36+
ability to detect some bugs. It is not expected to produce false positive
37+
reports.
38+
39+
## Examples
2640

2741
Stack buffer overflow:
2842

29-
```shell
30-
$ cat a.rs
43+
```rust
3144
fn main() {
3245
let xs = [0, 1, 2, 3];
3346
let _y = unsafe { *xs.as_ptr().offset(4) };
3447
}
35-
$ rustc -Zsanitizer=address a.rs
36-
$ ./a
37-
=================================================================
38-
==10029==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcc15f43d0 at pc 0x55f77dc015c5 bp 0x7ffcc15f4390 sp 0x7ffcc15f4388
39-
READ of size 4 at 0x7ffcc15f43d0 thread T0
40-
#0 0x55f77dc015c4 in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa5c4)
41-
#1 0x55f77dc01cdb in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::haa8c76d1faa7b7ca (/tmp/a+0xacdb)
42-
#2 0x55f77dc90f02 in std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::hfeb9a1aef9ac820d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:48:12
43-
#3 0x55f77dc90f02 in std::panicking::try::do_call::h12f0919717b8e0a6 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:288:39
44-
#4 0x55f77dc926c9 in __rust_maybe_catch_panic /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libpanic_unwind/lib.rs:80:7
45-
#5 0x55f77dc9197c in std::panicking::try::h413b21cdcd6cfd86 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:267:12
46-
#6 0x55f77dc9197c in std::panic::catch_unwind::hc5cc8ef2fd73424d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panic.rs:396:8
47-
#7 0x55f77dc9197c in std::rt::lang_start_internal::h2039f418ab92218f /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:47:24
48-
#8 0x55f77dc01c61 in std::rt::lang_start::ha905d28f6b61d691 (/tmp/a+0xac61)
49-
#9 0x55f77dc0163a in main (/tmp/a+0xa63a)
50-
#10 0x7f9b3cf5bbba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
51-
#11 0x55f77dc01289 in _start (/tmp/a+0xa289)
52-
53-
Address 0x7ffcc15f43d0 is located in stack of thread T0 at offset 48 in frame
54-
#0 0x55f77dc0135f in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa35f)
48+
```
49+
50+
```shell
51+
$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
52+
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
53+
==37882==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe400e6250 at pc 0x5609a841fb20 bp 0x7ffe400e6210 sp 0x7ffe400e6208
54+
READ of size 4 at 0x7ffe400e6250 thread T0
55+
#0 0x5609a841fb1f in example::main::h628ffc6626ed85b2 /.../src/main.rs:3:23
56+
...
57+
58+
Address 0x7ffe400e6250 is located in stack of thread T0 at offset 48 in frame
59+
#0 0x5609a841f8af in example::main::h628ffc6626ed85b2 /.../src/main.rs:1
5560

5661
This frame has 1 object(s):
57-
[32, 48) 'xs' <== Memory access at offset 48 overflows this variable
62+
[32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variable
5863
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
5964
(longjmp and C++ exceptions *are* supported)
60-
SUMMARY: AddressSanitizer: stack-buffer-overflow (/tmp/a+0xa5c4) in a::main::hab3bd2a745c2d0ac
65+
SUMMARY: AddressSanitizer: stack-buffer-overflow /.../src/main.rs:3:23 in example::main::h628ffc6626ed85b2
6166
Shadow bytes around the buggy address:
62-
0x1000182b6820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63-
0x1000182b6830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
64-
0x1000182b6840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
65-
0x1000182b6850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
66-
0x1000182b6860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
67-
=>0x1000182b6870: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
68-
0x1000182b6880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69-
0x1000182b6890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70-
0x1000182b68a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
71-
0x1000182b68b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
72-
0x1000182b68c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
67+
0x100048014bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
68+
0x100048014c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69+
0x100048014c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70+
0x100048014c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
71+
0x100048014c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
72+
=>0x100048014c40: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
73+
0x100048014c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
74+
0x100048014c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
75+
0x100048014c70: f1 f1 f1 f1 00 00 f3 f3 00 00 00 00 00 00 00 00
76+
0x100048014c80: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
77+
0x100048014c90: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
7378
Shadow byte legend (one shadow byte represents 8 application bytes):
7479
Addressable: 00
75-
Partially addressable: 01 02 03 04 05 06 07
80+
Partially addressable: 01 02 03 04 05 06 07
7681
Heap left redzone: fa
7782
Freed heap region: fd
7883
Stack left redzone: f1
@@ -90,13 +95,12 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
9095
Left alloca redzone: ca
9196
Right alloca redzone: cb
9297
Shadow gap: cc
93-
==10029==ABORTING
98+
==37882==ABORTING
9499
```
95100
96101
Use of a stack object after its scope has already ended:
97102
98-
```shell
99-
$ cat b.rs
103+
```rust
100104
static mut P: *mut usize = std::ptr::null_mut();
101105

102106
fn main() {
@@ -108,42 +112,38 @@ fn main() {
108112
std::ptr::write_volatile(P, 123);
109113
}
110114
}
111-
$ rustc -Zsanitizer=address b.rs
112-
$./b
115+
```
116+
117+
```shell
118+
$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
119+
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
113120
=================================================================
114-
==424427==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fff67be6be0 at pc 0x5647a3ea4658 bp 0x7fff67be6b90 sp 0x7fff67be6b88
115-
WRITE of size 8 at 0x7fff67be6be0 thread T0
116-
#0 0x5647a3ea4657 in core::ptr::write_volatile::h4b04601757d0376d (/tmp/b+0xb8657)
117-
#1 0x5647a3ea4432 in b::main::h5574a756e615c9cf (/tmp/b+0xb8432)
118-
#2 0x5647a3ea480b in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd57e7ee01866077e (/tmp/b+0xb880b)
119-
#3 0x5647a3eab412 in std::panicking::try::do_call::he0421ca82dd11ba3 (.llvm.8083791802951296215) (/tmp/b+0xbf412)
120-
#4 0x5647a3eacb26 in __rust_maybe_catch_panic (/tmp/b+0xc0b26)
121-
#5 0x5647a3ea5b66 in std::rt::lang_start_internal::h19bc96b28f670a64 (/tmp/b+0xb9b66)
122-
#6 0x5647a3ea4788 in std::rt::lang_start::h642d10b4b6965fb8 (/tmp/b+0xb8788)
123-
#7 0x5647a3ea449a in main (/tmp/b+0xb849a)
124-
#8 0x7fd1d18b3bba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
125-
#9 0x5647a3df7299 in _start (/tmp/b+0xb299)
126-
127-
Address 0x7fff67be6be0 is located in stack of thread T0 at offset 32 in frame
128-
#0 0x5647a3ea433f in b::main::h5574a756e615c9cf (/tmp/b+0xb833f)
121+
==39249==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc7ed3e1a0 at pc 0x55c98b262a8e bp 0x7ffc7ed3e050 sp 0x7ffc7ed3e048
122+
WRITE of size 8 at 0x7ffc7ed3e1a0 thread T0
123+
#0 0x55c98b262a8d in core::ptr::write_volatile::he21f1df5a82f329a /.../src/rust/src/libcore/ptr/mod.rs:1048:5
124+
#1 0x55c98b262cd2 in example::main::h628ffc6626ed85b2 /.../src/main.rs:9:9
125+
...
126+
127+
Address 0x7ffc7ed3e1a0 is located in stack of thread T0 at offset 32 in frame
128+
#0 0x55c98b262bdf in example::main::h628ffc6626ed85b2 /.../src/main.rs:3
129129

130130
This frame has 1 object(s):
131-
[32, 40) 'x' <== Memory access at offset 32 is inside this variable
131+
[32, 40) 'x' (line 6) <== Memory access at offset 32 is inside this variable
132132
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
133133
(longjmp and C++ exceptions *are* supported)
134-
SUMMARY: AddressSanitizer: stack-use-after-scope (/tmp/b+0xb8657) in core::ptr::write_volatile::h4b04601757d0376d
134+
SUMMARY: AddressSanitizer: stack-use-after-scope /.../src/rust/src/libcore/ptr/mod.rs:1048:5 in core::ptr::write_volatile::he21f1df5a82f329a
135135
Shadow bytes around the buggy address:
136-
0x10006cf74d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
137-
0x10006cf74d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
138-
0x10006cf74d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
139-
0x10006cf74d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
140-
0x10006cf74d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
141-
=>0x10006cf74d70: 00 00 00 00 00 00 00 00 f1 f1 f1 f1[f8]f3 f3 f3
142-
0x10006cf74d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
143-
0x10006cf74d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
144-
0x10006cf74da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
145-
0x10006cf74db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
146-
0x10006cf74dc0: f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00 00 00 00 00
136+
0x10000fd9fbe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
137+
0x10000fd9fbf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
138+
0x10000fd9fc00: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
139+
0x10000fd9fc10: f8 f8 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
140+
0x10000fd9fc20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
141+
=>0x10000fd9fc30: f1 f1 f1 f1[f8]f3 f3 f3 00 00 00 00 00 00 00 00
142+
0x10000fd9fc40: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
143+
0x10000fd9fc50: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
144+
0x10000fd9fc60: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3
145+
0x10000fd9fc70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
146+
0x10000fd9fc80: 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3 00 00 00 00
147147
Shadow byte legend (one shadow byte represents 8 application bytes):
148148
Addressable: 00
149149
Partially addressable: 01 02 03 04 05 06 07
@@ -164,17 +164,26 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
164164
Left alloca redzone: ca
165165
Right alloca redzone: cb
166166
Shadow gap: cc
167-
==424427==ABORTING
167+
==39249==ABORTING
168168
```
169169
170-
## MemorySanitizer
170+
# MemorySanitizer
171+
172+
MemorySanitizer is detector of uninitialized reads. It is only supported on the
173+
`x86_64-unknown-linux-gnu` target.
174+
175+
MemorySanitizer requires all program code to be instrumented. C/C++ dependencies
176+
need to be recompiled using Clang with `-fsanitize=memory` option. Failing to
177+
achieve that will result in false positive reports.
178+
179+
## Example
171180
172-
Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument
173-
the standard library, and passing `-Zsanitizer-track-origins` to track the
181+
Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and
182+
instruments the standard library, and is strictly necessary for the correct
183+
operation of the tool. The `-Zsanitizer-track-origins` enables tracking of the
174184
origins of uninitialized memory:
175185
176-
```shell
177-
$ cat src/main.rs
186+
```rust
178187
use std::mem::MaybeUninit;
179188

180189
fn main() {
@@ -184,7 +193,9 @@ fn main() {
184193
println!("{}", a[2]);
185194
}
186195
}
196+
```
187197
198+
```shell
188199
$ export \
189200
CC=clang \
190201
CXX=clang++ \
@@ -193,7 +204,7 @@ $ export \
193204
RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \
194205
RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins'
195206
$ cargo clean
196-
$ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
207+
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
197208
==9416==WARNING: MemorySanitizer: use-of-uninitialized-value
198209
#0 0x560c04f7488a in core::fmt::num::imp::fmt_u64::haa293b0b098501ca $RUST/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/src/libcore/fmt/num.rs:202:16
199210
...
@@ -205,6 +216,55 @@ $ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
205216
#0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
206217
```
207218
219+
# ThreadSanitizer
220+
221+
ThreadSanitizer is a data race detection tool. It is supported on the following
222+
targets:
223+
224+
* `x86_64-apple-darwin`
225+
* `x86_64-unknown-linux-gnu`
226+
227+
To work correctly ThreadSanitizer needs to be "aware" of all synchronization
228+
operations in a program. It generally achieves that through combination of
229+
library interception (for example synchronization performed through
230+
`pthread_mutex_lock` / `pthread_mutex_unlock`) and compile time instrumentation
231+
(e.g. atomic operations). Using it without instrumenting all the program code
232+
can lead to false positive reports.
233+
234+
ThreadSanitizer does not support atomic fences `std::sync::atomic::fence`,
235+
nor synchronization performed using inline assembly code.
236+
237+
## Example
238+
239+
```rust
240+
static mut A: usize = 0;
241+
242+
fn main() {
243+
let t = std::thread::spawn(|| {
244+
unsafe { A += 1 };
245+
});
246+
unsafe { A += 1 };
247+
248+
t.join().unwrap();
249+
}
250+
```
251+
252+
```shell
253+
$ export RUSTFLAGS=-Zsanitizer=thread RUSTDOCFLAGS=-Zsanitizer=thread
254+
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
255+
==================
256+
WARNING: ThreadSanitizer: data race (pid=10574)
257+
Read of size 8 at 0x5632dfe3d030 by thread T1:
258+
#0 example::main::_$u7b$$u7b$closure$u7d$$u7d$::h23f64b0b2f8c9484 ../src/main.rs:5:18 (example+0x86cec)
259+
...
260+
261+
Previous write of size 8 at 0x5632dfe3d030 by main thread:
262+
#0 example::main::h628ffc6626ed85b2 /.../src/main.rs:7:14 (example+0x868c8)
263+
...
264+
#11 main <null> (example+0x86a1a)
265+
266+
Location is global 'example::A::h43ac149ddf992709' of size 8 at 0x5632dfe3d030 (example+0x000000bd9030)
267+
```
208268
209269
# Instrumentation of external dependencies and std
210270
@@ -231,6 +291,10 @@ In more practical terms when using cargo always remember to pass `--target`
231291
flag, so that rustflags will not be applied to build scripts and procedural
232292
macros.
233293
294+
# Symbolizing the Reports
295+
296+
Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PATH`.
297+
234298
# Additional Information
235299
236300
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)

‎src/liballoc/collections/vec_deque.rs

+153-52
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,9 @@ impl<T> VecDeque<T> {
959959
/// Returns a pair of slices which contain, in order, the contents of the
960960
/// `VecDeque`.
961961
///
962+
/// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements
963+
/// of the `VecDeque` will be in the first slice and the second slice will be empty.
964+
///
962965
/// # Examples
963966
///
964967
/// ```
@@ -989,6 +992,9 @@ impl<T> VecDeque<T> {
989992
/// Returns a pair of slices which contain, in order, the contents of the
990993
/// `VecDeque`.
991994
///
995+
/// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements
996+
/// of the `VecDeque` will be in the first slice and the second slice will be empty.
997+
///
992998
/// # Examples
993999
///
9941000
/// ```
@@ -2044,6 +2050,148 @@ impl<T> VecDeque<T> {
20442050
}
20452051
}
20462052

2053+
/// Rearranges the internal storage of this deque so it is one contiguous slice, which is then returned.
2054+
///
2055+
/// This method does not allocate and does not change the order of the inserted elements.
2056+
/// As it returns a mutable slice, this can be used to sort or binary search a deque.
2057+
///
2058+
/// Once the internal storage is contiguous, the [`as_slices`](#method.as_slices) and
2059+
/// [`as_mut_slices`](#method.as_mut_slices) methods will return the entire contents of the
2060+
/// `VecDeque` in a single slice.
2061+
///
2062+
/// # Examples
2063+
///
2064+
/// Sorting the content of a deque.
2065+
///
2066+
/// ```
2067+
/// #![feature(deque_make_contiguous)]
2068+
///
2069+
/// use std::collections::VecDeque;
2070+
///
2071+
/// let mut buf = VecDeque::with_capacity(15);
2072+
///
2073+
/// buf.push_back(2);
2074+
/// buf.push_back(1);
2075+
/// buf.push_front(3);
2076+
///
2077+
/// // sorting the deque
2078+
/// buf.make_contiguous().sort();
2079+
/// assert_eq!(buf.as_slices(), (&[1, 2, 3] as &[_], &[] as &[_]));
2080+
///
2081+
/// // sorting it in reverse order
2082+
/// buf.make_contiguous().sort_by(|a, b| b.cmp(a));
2083+
/// assert_eq!(buf.as_slices(), (&[3, 2, 1] as &[_], &[] as &[_]));
2084+
/// ```
2085+
///
2086+
/// Getting immutable access to the contiguous slice.
2087+
///
2088+
/// ```rust
2089+
/// #![feature(deque_make_contiguous)]
2090+
///
2091+
/// use std::collections::VecDeque;
2092+
///
2093+
/// let mut buf = VecDeque::new();
2094+
///
2095+
/// buf.push_back(2);
2096+
/// buf.push_back(1);
2097+
/// buf.push_front(3);
2098+
///
2099+
/// buf.make_contiguous();
2100+
/// if let (slice, &[]) = buf.as_slices() {
2101+
/// // we can now be sure that `slice` contains all elements of the deque,
2102+
/// // while still having immutable access to `buf`.
2103+
/// assert_eq!(buf.len(), slice.len());
2104+
/// assert_eq!(slice, &[3, 2, 1] as &[_]);
2105+
/// }
2106+
/// ```
2107+
#[unstable(feature = "deque_make_contiguous", issue = "none")]
2108+
pub fn make_contiguous(&mut self) -> &mut [T] {
2109+
if self.is_contiguous() {
2110+
let tail = self.tail;
2111+
let head = self.head;
2112+
return unsafe { &mut self.buffer_as_mut_slice()[tail..head] };
2113+
}
2114+
2115+
let buf = self.buf.ptr();
2116+
let cap = self.cap();
2117+
let len = self.len();
2118+
2119+
let free = self.tail - self.head;
2120+
let tail_len = cap - self.tail;
2121+
2122+
if free >= tail_len {
2123+
// there is enough free space to copy the tail in one go,
2124+
// this means that we first shift the head backwards, and then
2125+
// copy the tail to the correct position.
2126+
//
2127+
// from: DEFGH....ABC
2128+
// to: ABCDEFGH....
2129+
unsafe {
2130+
ptr::copy(buf, buf.add(tail_len), self.head);
2131+
// ...DEFGH.ABC
2132+
ptr::copy_nonoverlapping(buf.add(self.tail), buf, tail_len);
2133+
// ABCDEFGH....
2134+
2135+
self.tail = 0;
2136+
self.head = len;
2137+
}
2138+
} else if free >= self.head {
2139+
// there is enough free space to copy the head in one go,
2140+
// this means that we first shift the tail forwards, and then
2141+
// copy the head to the correct position.
2142+
//
2143+
// from: FGH....ABCDE
2144+
// to: ...ABCDEFGH.
2145+
unsafe {
2146+
ptr::copy(buf.add(self.tail), buf.add(self.head), tail_len);
2147+
// FGHABCDE....
2148+
ptr::copy_nonoverlapping(buf, buf.add(self.head + tail_len), self.head);
2149+
// ...ABCDEFGH.
2150+
2151+
self.tail = self.head;
2152+
self.head = self.tail + len;
2153+
}
2154+
} else {
2155+
// free is smaller than both head and tail,
2156+
// this means we have to slowly "swap" the tail and the head.
2157+
//
2158+
// from: EFGHI...ABCD or HIJK.ABCDEFG
2159+
// to: ABCDEFGHI... or ABCDEFGHIJK.
2160+
let mut left_edge: usize = 0;
2161+
let mut right_edge: usize = self.tail;
2162+
unsafe {
2163+
// The general problem looks like this
2164+
// GHIJKLM...ABCDEF - before any swaps
2165+
// ABCDEFM...GHIJKL - after 1 pass of swaps
2166+
// ABCDEFGHIJM...KL - swap until the left edge reaches the temp store
2167+
// - then restart the algorithm with a new (smaller) store
2168+
// Sometimes the temp store is reached when the right edge is at the end
2169+
// of the buffer - this means we've hit the right order with fewer swaps!
2170+
// E.g
2171+
// EF..ABCD
2172+
// ABCDEF.. - after four only swaps we've finished
2173+
while left_edge < len && right_edge != cap {
2174+
let mut right_offset = 0;
2175+
for i in left_edge..right_edge {
2176+
right_offset = (i - left_edge) % (cap - right_edge);
2177+
let src: isize = (right_edge + right_offset) as isize;
2178+
ptr::swap(buf.add(i), buf.offset(src));
2179+
}
2180+
let n_ops = right_edge - left_edge;
2181+
left_edge += n_ops;
2182+
right_edge += right_offset + 1;
2183+
}
2184+
2185+
self.tail = 0;
2186+
self.head = len;
2187+
}
2188+
}
2189+
2190+
let tail = self.tail;
2191+
let head = self.head;
2192+
unsafe { &mut self.buffer_as_mut_slice()[tail..head] }
2193+
}
2194+
20472195
/// Rotates the double-ended queue `mid` places to the left.
20482196
///
20492197
/// Equivalently,
@@ -2803,63 +2951,16 @@ impl<T> From<VecDeque<T>> for Vec<T> {
28032951
/// assert_eq!(vec, [8, 9, 1, 2, 3, 4]);
28042952
/// assert_eq!(vec.as_ptr(), ptr);
28052953
/// ```
2806-
fn from(other: VecDeque<T>) -> Self {
2954+
fn from(mut other: VecDeque<T>) -> Self {
2955+
other.make_contiguous();
2956+
28072957
unsafe {
28082958
let buf = other.buf.ptr();
28092959
let len = other.len();
2810-
let tail = other.tail;
2811-
let head = other.head;
28122960
let cap = other.cap();
28132961

2814-
// Need to move the ring to the front of the buffer, as vec will expect this.
2815-
if other.is_contiguous() {
2816-
ptr::copy(buf.add(tail), buf, len);
2817-
} else {
2818-
if (tail - head) >= cmp::min(cap - tail, head) {
2819-
// There is enough free space in the centre for the shortest block so we can
2820-
// do this in at most three copy moves.
2821-
if (cap - tail) > head {
2822-
// right hand block is the long one; move that enough for the left
2823-
ptr::copy(buf.add(tail), buf.add(tail - head), cap - tail);
2824-
// copy left in the end
2825-
ptr::copy(buf, buf.add(cap - head), head);
2826-
// shift the new thing to the start
2827-
ptr::copy(buf.add(tail - head), buf, len);
2828-
} else {
2829-
// left hand block is the long one, we can do it in two!
2830-
ptr::copy(buf, buf.add(cap - tail), head);
2831-
ptr::copy(buf.add(tail), buf, cap - tail);
2832-
}
2833-
} else {
2834-
// Need to use N swaps to move the ring
2835-
// We can use the space at the end of the ring as a temp store
2836-
2837-
let mut left_edge: usize = 0;
2838-
let mut right_edge: usize = tail;
2839-
2840-
// The general problem looks like this
2841-
// GHIJKLM...ABCDEF - before any swaps
2842-
// ABCDEFM...GHIJKL - after 1 pass of swaps
2843-
// ABCDEFGHIJM...KL - swap until the left edge reaches the temp store
2844-
// - then restart the algorithm with a new (smaller) store
2845-
// Sometimes the temp store is reached when the right edge is at the end
2846-
// of the buffer - this means we've hit the right order with fewer swaps!
2847-
// E.g
2848-
// EF..ABCD
2849-
// ABCDEF.. - after four only swaps we've finished
2850-
2851-
while left_edge < len && right_edge != cap {
2852-
let mut right_offset = 0;
2853-
for i in left_edge..right_edge {
2854-
right_offset = (i - left_edge) % (cap - right_edge);
2855-
let src: isize = (right_edge + right_offset) as isize;
2856-
ptr::swap(buf.add(i), buf.offset(src));
2857-
}
2858-
let n_ops = right_edge - left_edge;
2859-
left_edge += n_ops;
2860-
right_edge += right_offset + 1;
2861-
}
2862-
}
2962+
if other.head != 0 {
2963+
ptr::copy(buf.add(other.tail), buf, len);
28632964
}
28642965
let out = Vec::from_raw_parts(buf, len, cap);
28652966
mem::forget(other);

‎src/liballoc/collections/vec_deque/tests.rs

+82-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::*;
22

3-
use ::test;
3+
use test;
44

55
#[bench]
66
#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
@@ -130,6 +130,87 @@ fn test_insert() {
130130
}
131131
}
132132

133+
#[test]
134+
fn make_contiguous_big_tail() {
135+
let mut tester = VecDeque::with_capacity(15);
136+
137+
for i in 0..3 {
138+
tester.push_back(i);
139+
}
140+
141+
for i in 3..10 {
142+
tester.push_front(i);
143+
}
144+
145+
// 012......9876543
146+
assert_eq!(tester.capacity(), 15);
147+
assert_eq!((&[9, 8, 7, 6, 5, 4, 3] as &[_], &[0, 1, 2] as &[_]), tester.as_slices());
148+
149+
let expected_start = tester.head;
150+
tester.make_contiguous();
151+
assert_eq!(tester.tail, expected_start);
152+
assert_eq!((&[9, 8, 7, 6, 5, 4, 3, 0, 1, 2] as &[_], &[] as &[_]), tester.as_slices());
153+
}
154+
155+
#[test]
156+
fn make_contiguous_big_head() {
157+
let mut tester = VecDeque::with_capacity(15);
158+
159+
for i in 0..8 {
160+
tester.push_back(i);
161+
}
162+
163+
for i in 8..10 {
164+
tester.push_front(i);
165+
}
166+
167+
// 01234567......98
168+
let expected_start = 0;
169+
tester.make_contiguous();
170+
assert_eq!(tester.tail, expected_start);
171+
assert_eq!((&[9, 8, 0, 1, 2, 3, 4, 5, 6, 7] as &[_], &[] as &[_]), tester.as_slices());
172+
}
173+
174+
#[test]
175+
fn make_contiguous_small_free() {
176+
let mut tester = VecDeque::with_capacity(15);
177+
178+
for i in 'A' as u8..'I' as u8 {
179+
tester.push_back(i as char);
180+
}
181+
182+
for i in 'I' as u8..'N' as u8 {
183+
tester.push_front(i as char);
184+
}
185+
186+
// ABCDEFGH...MLKJI
187+
let expected_start = 0;
188+
tester.make_contiguous();
189+
assert_eq!(tester.tail, expected_start);
190+
assert_eq!(
191+
(&['M', 'L', 'K', 'J', 'I', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] as &[_], &[] as &[_]),
192+
tester.as_slices()
193+
);
194+
195+
tester.clear();
196+
for i in 'I' as u8..'N' as u8 {
197+
tester.push_back(i as char);
198+
}
199+
200+
for i in 'A' as u8..'I' as u8 {
201+
tester.push_front(i as char);
202+
}
203+
204+
// IJKLM...HGFEDCBA
205+
let expected_start = 0;
206+
tester.make_contiguous();
207+
assert_eq!(tester.tail, expected_start);
208+
assert_eq!(
209+
(&['H', 'G', 'F', 'E', 'D', 'C', 'B', 'A', 'I', 'J', 'K', 'L', 'M'] as &[_], &[] as &[_]),
210+
tester.as_slices()
211+
);
212+
}
213+
133214
#[test]
134215
fn test_remove() {
135216
// This test checks that every single combination of tail position, length, and

‎src/librustc_error_codes/error_codes/E0466.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Macro import declarations were malformed.
1+
Macro import declaration was malformed.
22

33
Erroneous code examples:
44

‎src/librustc_mir/transform/const_prop.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -274,19 +274,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
274274
_memory_extra: &(),
275275
_alloc_id: AllocId,
276276
allocation: &Allocation<Self::PointerTag, Self::AllocExtra>,
277-
static_def_id: Option<DefId>,
277+
_static_def_id: Option<DefId>,
278278
is_write: bool,
279279
) -> InterpResult<'tcx> {
280280
if is_write {
281281
throw_machine_stop_str!("can't write to global");
282282
}
283-
// If the static allocation is mutable or if it has relocations (it may be legal to mutate
284-
// the memory behind that in the future), then we can't const prop it.
283+
// If the static allocation is mutable, then we can't const prop it as its content
284+
// might be different at runtime.
285285
if allocation.mutability == Mutability::Mut {
286-
throw_machine_stop_str!("can't eval mutable globals in ConstProp");
287-
}
288-
if static_def_id.is_some() && allocation.relocations().len() > 0 {
289-
throw_machine_stop_str!("can't eval statics with pointers in ConstProp");
286+
throw_machine_stop_str!("can't access mutable globals in ConstProp");
290287
}
291288

292289
Ok(())

‎src/librustdoc/test.rs

+63-40
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_span::source_map::SourceMap;
1313
use rustc_span::symbol::sym;
1414
use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
1515
use rustc_target::spec::TargetTriple;
16+
use std::collections::HashMap;
1617
use std::env;
1718
use std::io::{self, Write};
1819
use std::panic;
@@ -190,10 +191,23 @@ enum TestFailure {
190191
UnexpectedRunPass,
191192
}
192193

194+
enum DirState {
195+
Temp(tempfile::TempDir),
196+
Perm(PathBuf),
197+
}
198+
199+
impl DirState {
200+
fn path(&self) -> &std::path::Path {
201+
match self {
202+
DirState::Temp(t) => t.path(),
203+
DirState::Perm(p) => p.as_path(),
204+
}
205+
}
206+
}
207+
193208
fn run_test(
194209
test: &str,
195210
cratename: &str,
196-
filename: &FileName,
197211
line: usize,
198212
options: Options,
199213
should_panic: bool,
@@ -206,47 +220,11 @@ fn run_test(
206220
mut error_codes: Vec<String>,
207221
opts: &TestOptions,
208222
edition: Edition,
223+
outdir: DirState,
224+
path: PathBuf,
209225
) -> Result<(), TestFailure> {
210226
let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts, edition);
211227

212-
// FIXME(#44940): if doctests ever support path remapping, then this filename
213-
// needs to be the result of `SourceMap::span_to_unmapped_path`.
214-
let path = match filename {
215-
FileName::Real(path) => path.clone(),
216-
_ => PathBuf::from(r"doctest.rs"),
217-
};
218-
219-
enum DirState {
220-
Temp(tempfile::TempDir),
221-
Perm(PathBuf),
222-
}
223-
224-
impl DirState {
225-
fn path(&self) -> &std::path::Path {
226-
match self {
227-
DirState::Temp(t) => t.path(),
228-
DirState::Perm(p) => p.as_path(),
229-
}
230-
}
231-
}
232-
233-
let outdir = if let Some(mut path) = options.persist_doctests {
234-
path.push(format!(
235-
"{}_{}",
236-
filename.to_string().rsplit('/').next().unwrap().replace(".", "_"),
237-
line
238-
));
239-
std::fs::create_dir_all(&path).expect("Couldn't create directory for doctest executables");
240-
241-
DirState::Perm(path)
242-
} else {
243-
DirState::Temp(
244-
TempFileBuilder::new()
245-
.prefix("rustdoctest")
246-
.tempdir()
247-
.expect("rustdoc needs a tempdir"),
248-
)
249-
};
250228
let output_file = outdir.path().join("rust_out");
251229

252230
let rustc_binary = options
@@ -639,6 +617,7 @@ pub struct Collector {
639617
position: Span,
640618
source_map: Option<Lrc<SourceMap>>,
641619
filename: Option<PathBuf>,
620+
visited_tests: HashMap<(String, usize), usize>,
642621
}
643622

644623
impl Collector {
@@ -662,6 +641,7 @@ impl Collector {
662641
position: DUMMY_SP,
663642
source_map,
664643
filename,
644+
visited_tests: HashMap::new(),
665645
}
666646
}
667647

@@ -705,6 +685,48 @@ impl Tester for Collector {
705685
let target = self.options.target.clone();
706686
let target_str = target.to_string();
707687

688+
// FIXME(#44940): if doctests ever support path remapping, then this filename
689+
// needs to be the result of `SourceMap::span_to_unmapped_path`.
690+
let path = match &filename {
691+
FileName::Real(path) => path.clone(),
692+
_ => PathBuf::from(r"doctest.rs"),
693+
};
694+
695+
let outdir = if let Some(mut path) = options.persist_doctests.clone() {
696+
// For example `module/file.rs` would become `module_file_rs`
697+
let folder_name = filename
698+
.to_string()
699+
.chars()
700+
.map(|c| if c == '/' || c == '.' { '_' } else { c })
701+
.collect::<String>();
702+
703+
path.push(format!(
704+
"{name}_{line}_{number}",
705+
name = folder_name,
706+
number = {
707+
// Increases the current test number, if this file already
708+
// exists or it creates a new entry with a test number of 0.
709+
self.visited_tests
710+
.entry((folder_name.clone(), line))
711+
.and_modify(|v| *v += 1)
712+
.or_insert(0)
713+
},
714+
line = line,
715+
));
716+
717+
std::fs::create_dir_all(&path)
718+
.expect("Couldn't create directory for doctest executables");
719+
720+
DirState::Perm(path)
721+
} else {
722+
DirState::Temp(
723+
TempFileBuilder::new()
724+
.prefix("rustdoctest")
725+
.tempdir()
726+
.expect("rustdoc needs a tempdir"),
727+
)
728+
};
729+
708730
debug!("creating test {}: {}", name, test);
709731
self.tests.push(testing::TestDescAndFn {
710732
desc: testing::TestDesc {
@@ -723,7 +745,6 @@ impl Tester for Collector {
723745
let res = run_test(
724746
&test,
725747
&cratename,
726-
&filename,
727748
line,
728749
options,
729750
config.should_panic,
@@ -736,6 +757,8 @@ impl Tester for Collector {
736757
config.error_codes,
737758
&opts,
738759
edition,
760+
outdir,
761+
path,
739762
);
740763

741764
if let Err(err) = res {

‎src/test/ui/intrinsics/intrinsic-alignment.rs

-10
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,6 @@ mod m {
5656
#[cfg(target_os = "windows")]
5757
mod m {
5858
#[main]
59-
#[cfg(target_arch = "x86")]
60-
pub fn main() {
61-
unsafe {
62-
assert_eq!(::rusti::pref_align_of::<u64>(), 8);
63-
assert_eq!(::rusti::min_align_of::<u64>(), 8);
64-
}
65-
}
66-
67-
#[main]
68-
#[cfg(target_arch = "x86_64")]
6959
pub fn main() {
7060
unsafe {
7161
assert_eq!(::rusti::pref_align_of::<u64>(), 8);

‎src/test/ui/structs-enums/rec-align-u64.rs

-7
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,6 @@ mod m {
6767

6868
#[cfg(target_os = "windows")]
6969
mod m {
70-
#[cfg(target_arch = "x86")]
71-
pub mod m {
72-
pub fn align() -> usize { 8 }
73-
pub fn size() -> usize { 16 }
74-
}
75-
76-
#[cfg(target_arch = "x86_64")]
7770
pub mod m {
7871
pub fn align() -> usize { 8 }
7972
pub fn size() -> usize { 16 }

0 commit comments

Comments
 (0)
Please sign in to comment.