about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-03-31 19:12:14 +0000
committerbors <bors@rust-lang.org>2020-03-31 19:12:14 +0000
commita5b09d35473615e7142f5570f5c5fad0caf68bd2 (patch)
tree251cbaeb04db25a9a11452b69625b0e0d3abe107
parent75ff3110ac6d8a0259023b83fd20d7ab295f8dd6 (diff)
parent011c0906cde560631b35bd767c39d48ac17b1d39 (diff)
downloadrust-a5b09d35473615e7142f5570f5c5fad0caf68bd2.tar.gz
rust-a5b09d35473615e7142f5570f5c5fad0caf68bd2.zip
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
-rw-r--r--README.md2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md236
-rw-r--r--src/liballoc/collections/vec_deque.rs205
-rw-r--r--src/liballoc/collections/vec_deque/tests.rs83
-rw-r--r--src/librustc_error_codes/error_codes/E0466.md2
-rw-r--r--src/librustc_mir/transform/const_prop.rs11
-rw-r--r--src/librustdoc/test.rs103
-rw-r--r--src/test/ui/intrinsics/intrinsic-alignment.rs10
-rw-r--r--src/test/ui/structs-enums/rec-align-u64.rs7
9 files changed, 454 insertions, 205 deletions
diff --git a/README.md b/README.md
index 1cd9b8a3a2a..6f184e25218 100644
--- a/README.md
+++ b/README.md
@@ -256,7 +256,7 @@ Also, you may find the [rustdocs for the compiler itself][rustdocs] useful.
 
 [rust-discord]: https://discord.gg/rust-lang
 [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/about-this-guide.html
-[rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/
+[rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/
 
 ## License
 
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 414ac7e63a3..7ebd8054ba0 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -6,73 +6,78 @@ The tracking issue for this feature is: [#39699](https://github.com/rust-lang/ru
 
 This feature allows for use of one of following sanitizers:
 
-* [AddressSanitizer][clang-asan] a faster memory error detector. Can
-  detect out-of-bounds access to heap, stack, and globals, use after free, use
-  after return, double free, invalid free, memory leaks.
+* [AddressSanitizer][clang-asan] a fast memory error detector.
 * [LeakSanitizer][clang-lsan] a run-time memory leak detector.
 * [MemorySanitizer][clang-msan] a detector of uninitialized reads.
 * [ThreadSanitizer][clang-tsan] a fast data race detector.
 
-To enable a sanitizer compile with `-Zsanitizer=...` option, where value is one
-of `address`, `leak`, `memory` or `thread`.
+To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
+`-Zsanitizer=memory` or `-Zsanitizer=thread`. Only a single sanitizer can be
+enabled at a time.
 
-# Examples
+# AddressSanitizer
 
-This sections show various issues that can be detected with sanitizers.  For
-simplicity, the examples are prepared under assumption that optimization level
-used is zero.
+AddressSanitizer is a memory error detector. It can detect the following types
+of bugs:
 
-## AddressSanitizer
+* Out of bound accesses to heap, stack and globals
+* Use after free
+* Use after return (runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1`)
+* Use after scope
+* Double-free, invalid free
+* Memory leaks
+
+AddressSanitizer is supported on the following targets:
+
+* `x86_64-apple-darwin`
+* `x86_64-unknown-linux-gnu`
+
+AddressSanitizer works with non-instrumented code although it will impede its
+ability to detect some bugs.  It is not expected to produce false positive
+reports.
+
+## Examples
 
 Stack buffer overflow:
 
-```shell
-$ cat a.rs
+```rust
 fn main() {
     let xs = [0, 1, 2, 3];
     let _y = unsafe { *xs.as_ptr().offset(4) };
 }
-$ rustc -Zsanitizer=address a.rs
-$ ./a
-=================================================================
-==10029==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcc15f43d0 at pc 0x55f77dc015c5 bp 0x7ffcc15f4390 sp 0x7ffcc15f4388
-READ of size 4 at 0x7ffcc15f43d0 thread T0
-    #0 0x55f77dc015c4 in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa5c4)
-    #1 0x55f77dc01cdb in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::haa8c76d1faa7b7ca (/tmp/a+0xacdb)
-    #2 0x55f77dc90f02 in std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::hfeb9a1aef9ac820d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:48:12
-    #3 0x55f77dc90f02 in std::panicking::try::do_call::h12f0919717b8e0a6 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:288:39
-    #4 0x55f77dc926c9 in __rust_maybe_catch_panic /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libpanic_unwind/lib.rs:80:7
-    #5 0x55f77dc9197c in std::panicking::try::h413b21cdcd6cfd86 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:267:12
-    #6 0x55f77dc9197c in std::panic::catch_unwind::hc5cc8ef2fd73424d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panic.rs:396:8
-    #7 0x55f77dc9197c in std::rt::lang_start_internal::h2039f418ab92218f /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:47:24
-    #8 0x55f77dc01c61 in std::rt::lang_start::ha905d28f6b61d691 (/tmp/a+0xac61)
-    #9 0x55f77dc0163a in main (/tmp/a+0xa63a)
-    #10 0x7f9b3cf5bbba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
-    #11 0x55f77dc01289 in _start (/tmp/a+0xa289)
-
-Address 0x7ffcc15f43d0 is located in stack of thread T0 at offset 48 in frame
-    #0 0x55f77dc0135f in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa35f)
+```
+
+```shell
+$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
+$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
+==37882==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe400e6250 at pc 0x5609a841fb20 bp 0x7ffe400e6210 sp 0x7ffe400e6208
+READ of size 4 at 0x7ffe400e6250 thread T0
+    #0 0x5609a841fb1f in example::main::h628ffc6626ed85b2 /.../src/main.rs:3:23
+    ...
+
+Address 0x7ffe400e6250 is located in stack of thread T0 at offset 48 in frame
+    #0 0x5609a841f8af in example::main::h628ffc6626ed85b2 /.../src/main.rs:1
 
   This frame has 1 object(s):
-    [32, 48) 'xs' <== Memory access at offset 48 overflows this variable
+    [32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variable
 HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
       (longjmp and C++ exceptions *are* supported)
-SUMMARY: AddressSanitizer: stack-buffer-overflow (/tmp/a+0xa5c4) in a::main::hab3bd2a745c2d0ac
+SUMMARY: AddressSanitizer: stack-buffer-overflow /.../src/main.rs:3:23 in example::main::h628ffc6626ed85b2
 Shadow bytes around the buggy address:
-  0x1000182b6820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b6830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b6840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b6850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b6860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-=>0x1000182b6870: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
-  0x1000182b6880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b6890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b68a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b68b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x1000182b68c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x100048014bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x100048014c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x100048014c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x100048014c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x100048014c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+=>0x100048014c40: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
+  0x100048014c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x100048014c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x100048014c70: f1 f1 f1 f1 00 00 f3 f3 00 00 00 00 00 00 00 00
+  0x100048014c80: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
+  0x100048014c90: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
 Shadow byte legend (one shadow byte represents 8 application bytes):
   Addressable:           00
-  Partially addressable: 01 02 03 04 05 06 07 
+  Partially addressable: 01 02 03 04 05 06 07
   Heap left redzone:       fa
   Freed heap region:       fd
   Stack left redzone:      f1
@@ -90,13 +95,12 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
   Left alloca redzone:     ca
   Right alloca redzone:    cb
   Shadow gap:              cc
-==10029==ABORTING
+==37882==ABORTING
 ```
 
 Use of a stack object after its scope has already ended:
 
-```shell
-$ cat b.rs
+```rust
 static mut P: *mut usize = std::ptr::null_mut();
 
 fn main() {
@@ -108,42 +112,38 @@ fn main() {
         std::ptr::write_volatile(P, 123);
     }
 }
-$ rustc -Zsanitizer=address b.rs
-$./b
+```
+
+```shell
+$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
+$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
 =================================================================
-==424427==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fff67be6be0 at pc 0x5647a3ea4658 bp 0x7fff67be6b90 sp 0x7fff67be6b88
-WRITE of size 8 at 0x7fff67be6be0 thread T0
-    #0 0x5647a3ea4657 in core::ptr::write_volatile::h4b04601757d0376d (/tmp/b+0xb8657)
-    #1 0x5647a3ea4432 in b::main::h5574a756e615c9cf (/tmp/b+0xb8432)
-    #2 0x5647a3ea480b in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd57e7ee01866077e (/tmp/b+0xb880b)
-    #3 0x5647a3eab412 in std::panicking::try::do_call::he0421ca82dd11ba3 (.llvm.8083791802951296215) (/tmp/b+0xbf412)
-    #4 0x5647a3eacb26 in __rust_maybe_catch_panic (/tmp/b+0xc0b26)
-    #5 0x5647a3ea5b66 in std::rt::lang_start_internal::h19bc96b28f670a64 (/tmp/b+0xb9b66)
-    #6 0x5647a3ea4788 in std::rt::lang_start::h642d10b4b6965fb8 (/tmp/b+0xb8788)
-    #7 0x5647a3ea449a in main (/tmp/b+0xb849a)
-    #8 0x7fd1d18b3bba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
-    #9 0x5647a3df7299 in _start (/tmp/b+0xb299)
-
-Address 0x7fff67be6be0 is located in stack of thread T0 at offset 32 in frame
-    #0 0x5647a3ea433f in b::main::h5574a756e615c9cf (/tmp/b+0xb833f)
+==39249==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc7ed3e1a0 at pc 0x55c98b262a8e bp 0x7ffc7ed3e050 sp 0x7ffc7ed3e048
+WRITE of size 8 at 0x7ffc7ed3e1a0 thread T0
+    #0 0x55c98b262a8d in core::ptr::write_volatile::he21f1df5a82f329a /.../src/rust/src/libcore/ptr/mod.rs:1048:5
+    #1 0x55c98b262cd2 in example::main::h628ffc6626ed85b2 /.../src/main.rs:9:9
+    ...
+
+Address 0x7ffc7ed3e1a0 is located in stack of thread T0 at offset 32 in frame
+    #0 0x55c98b262bdf in example::main::h628ffc6626ed85b2 /.../src/main.rs:3
 
   This frame has 1 object(s):
-    [32, 40) 'x' <== Memory access at offset 32 is inside this variable
+    [32, 40) 'x' (line 6) <== Memory access at offset 32 is inside this variable
 HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
       (longjmp and C++ exceptions *are* supported)
-SUMMARY: AddressSanitizer: stack-use-after-scope (/tmp/b+0xb8657) in core::ptr::write_volatile::h4b04601757d0376d
+SUMMARY: AddressSanitizer: stack-use-after-scope /.../src/rust/src/libcore/ptr/mod.rs:1048:5 in core::ptr::write_volatile::he21f1df5a82f329a
 Shadow bytes around the buggy address:
-  0x10006cf74d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-=>0x10006cf74d70: 00 00 00 00 00 00 00 00 f1 f1 f1 f1[f8]f3 f3 f3
-  0x10006cf74d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-  0x10006cf74dc0: f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00 00 00 00 00
+  0x10000fd9fbe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x10000fd9fbf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x10000fd9fc00: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
+  0x10000fd9fc10: f8 f8 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
+  0x10000fd9fc20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+=>0x10000fd9fc30: f1 f1 f1 f1[f8]f3 f3 f3 00 00 00 00 00 00 00 00
+  0x10000fd9fc40: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
+  0x10000fd9fc50: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
+  0x10000fd9fc60: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3
+  0x10000fd9fc70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x10000fd9fc80: 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3 00 00 00 00
 Shadow byte legend (one shadow byte represents 8 application bytes):
   Addressable:           00
   Partially addressable: 01 02 03 04 05 06 07
@@ -164,17 +164,26 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
   Left alloca redzone:     ca
   Right alloca redzone:    cb
   Shadow gap:              cc
-==424427==ABORTING
+==39249==ABORTING
 ```
 
-## MemorySanitizer
+# MemorySanitizer
+
+MemorySanitizer is detector of uninitialized reads. It is only supported on the
+`x86_64-unknown-linux-gnu` target.
+
+MemorySanitizer requires all program code to be instrumented. C/C++ dependencies
+need to be recompiled using Clang with `-fsanitize=memory` option. Failing to
+achieve that will result in false positive reports.
+
+## Example
 
-Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument
-the standard library, and passing `-Zsanitizer-track-origins` to track the
+Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and
+instruments the standard library, and is strictly necessary for the correct
+operation of the tool. The `-Zsanitizer-track-origins` enables tracking of the
 origins of uninitialized memory:
 
-```shell
-$ cat src/main.rs
+```rust
 use std::mem::MaybeUninit;
 
 fn main() {
@@ -184,7 +193,9 @@ fn main() {
         println!("{}", a[2]);
     }
 }
+```
 
+```shell
 $ export \
   CC=clang \
   CXX=clang++ \
@@ -193,7 +204,7 @@ $ export \
   RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \
   RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins'
 $ cargo clean
-$ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
+$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
 ==9416==WARNING: MemorySanitizer: use-of-uninitialized-value
     #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
 ...
@@ -205,6 +216,55 @@ $ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
     #0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
 ```
 
+# ThreadSanitizer
+
+ThreadSanitizer is a data race detection tool. It is supported on the following
+targets:
+
+* `x86_64-apple-darwin`
+* `x86_64-unknown-linux-gnu`
+
+To work correctly ThreadSanitizer needs to be "aware" of all synchronization
+operations in a program. It generally achieves that through combination of
+library interception (for example synchronization performed through
+`pthread_mutex_lock` / `pthread_mutex_unlock`) and compile time instrumentation
+(e.g. atomic operations). Using it without instrumenting all the program code
+can lead to false positive reports.
+
+ThreadSanitizer does not support atomic fences `std::sync::atomic::fence`,
+nor synchronization performed using inline assembly code.
+
+## Example
+
+```rust
+static mut A: usize = 0;
+
+fn main() {
+    let t = std::thread::spawn(|| {
+        unsafe { A += 1 };
+    });
+    unsafe { A += 1 };
+
+    t.join().unwrap();
+}
+```
+
+```shell
+$ export RUSTFLAGS=-Zsanitizer=thread RUSTDOCFLAGS=-Zsanitizer=thread
+$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
+==================
+WARNING: ThreadSanitizer: data race (pid=10574)
+  Read of size 8 at 0x5632dfe3d030 by thread T1:
+    #0 example::main::_$u7b$$u7b$closure$u7d$$u7d$::h23f64b0b2f8c9484 ../src/main.rs:5:18 (example+0x86cec)
+    ...
+
+  Previous write of size 8 at 0x5632dfe3d030 by main thread:
+    #0 example::main::h628ffc6626ed85b2 /.../src/main.rs:7:14 (example+0x868c8)
+    ...
+    #11 main <null> (example+0x86a1a)
+
+  Location is global 'example::A::h43ac149ddf992709' of size 8 at 0x5632dfe3d030 (example+0x000000bd9030)
+```
 
 # Instrumentation of external dependencies and std
 
@@ -231,6 +291,10 @@ In more practical terms when using cargo always remember to pass `--target`
 flag, so that rustflags will not be applied to build scripts and procedural
 macros.
 
+# Symbolizing the Reports
+
+Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PATH`.
+
 # Additional Information
 
 * [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 69284fbf1b3..94532521a90 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -959,6 +959,9 @@ impl<T> VecDeque<T> {
     /// Returns a pair of slices which contain, in order, the contents of the
     /// `VecDeque`.
     ///
+    /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements
+    /// of the `VecDeque` will be in the first slice and the second slice will be empty.
+    ///
     /// # Examples
     ///
     /// ```
@@ -989,6 +992,9 @@ impl<T> VecDeque<T> {
     /// Returns a pair of slices which contain, in order, the contents of the
     /// `VecDeque`.
     ///
+    /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements
+    /// of the `VecDeque` will be in the first slice and the second slice will be empty.
+    ///
     /// # Examples
     ///
     /// ```
@@ -2044,6 +2050,148 @@ impl<T> VecDeque<T> {
         }
     }
 
+    /// Rearranges the internal storage of this deque so it is one contiguous slice, which is then returned.
+    ///
+    /// This method does not allocate and does not change the order of the inserted elements.
+    /// As it returns a mutable slice, this can be used to sort or binary search a deque.
+    ///
+    /// Once the internal storage is contiguous, the [`as_slices`](#method.as_slices) and
+    /// [`as_mut_slices`](#method.as_mut_slices) methods will return the entire contents of the
+    /// `VecDeque` in a single slice.
+    ///
+    /// # Examples
+    ///
+    /// Sorting the content of a deque.
+    ///
+    /// ```
+    /// #![feature(deque_make_contiguous)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf = VecDeque::with_capacity(15);
+    ///
+    /// buf.push_back(2);
+    /// buf.push_back(1);
+    /// buf.push_front(3);
+    ///
+    /// // sorting the deque
+    /// buf.make_contiguous().sort();
+    /// assert_eq!(buf.as_slices(), (&[1, 2, 3] as &[_], &[] as &[_]));
+    ///
+    /// // sorting it in reverse order
+    /// buf.make_contiguous().sort_by(|a, b| b.cmp(a));
+    /// assert_eq!(buf.as_slices(), (&[3, 2, 1] as &[_], &[] as &[_]));
+    /// ```
+    ///
+    /// Getting immutable access to the contiguous slice.
+    ///
+    /// ```rust
+    /// #![feature(deque_make_contiguous)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf = VecDeque::new();
+    ///
+    /// buf.push_back(2);
+    /// buf.push_back(1);
+    /// buf.push_front(3);
+    ///
+    /// buf.make_contiguous();
+    /// if let (slice, &[]) = buf.as_slices() {
+    ///     // we can now be sure that `slice` contains all elements of the deque,
+    ///     // while still having immutable access to `buf`.
+    ///     assert_eq!(buf.len(), slice.len());
+    ///     assert_eq!(slice, &[3, 2, 1] as &[_]);
+    /// }
+    /// ```
+    #[unstable(feature = "deque_make_contiguous", issue = "none")]
+    pub fn make_contiguous(&mut self) -> &mut [T] {
+        if self.is_contiguous() {
+            let tail = self.tail;
+            let head = self.head;
+            return unsafe { &mut self.buffer_as_mut_slice()[tail..head] };
+        }
+
+        let buf = self.buf.ptr();
+        let cap = self.cap();
+        let len = self.len();
+
+        let free = self.tail - self.head;
+        let tail_len = cap - self.tail;
+
+        if free >= tail_len {
+            // there is enough free space to copy the tail in one go,
+            // this means that we first shift the head backwards, and then
+            // copy the tail to the correct position.
+            //
+            // from: DEFGH....ABC
+            // to:   ABCDEFGH....
+            unsafe {
+                ptr::copy(buf, buf.add(tail_len), self.head);
+                // ...DEFGH.ABC
+                ptr::copy_nonoverlapping(buf.add(self.tail), buf, tail_len);
+                // ABCDEFGH....
+
+                self.tail = 0;
+                self.head = len;
+            }
+        } else if free >= self.head {
+            // there is enough free space to copy the head in one go,
+            // this means that we first shift the tail forwards, and then
+            // copy the head to the correct position.
+            //
+            // from: FGH....ABCDE
+            // to:   ...ABCDEFGH.
+            unsafe {
+                ptr::copy(buf.add(self.tail), buf.add(self.head), tail_len);
+                // FGHABCDE....
+                ptr::copy_nonoverlapping(buf, buf.add(self.head + tail_len), self.head);
+                // ...ABCDEFGH.
+
+                self.tail = self.head;
+                self.head = self.tail + len;
+            }
+        } else {
+            // free is smaller than both head and tail,
+            // this means we have to slowly "swap" the tail and the head.
+            //
+            // from: EFGHI...ABCD or HIJK.ABCDEFG
+            // to:   ABCDEFGHI... or ABCDEFGHIJK.
+            let mut left_edge: usize = 0;
+            let mut right_edge: usize = self.tail;
+            unsafe {
+                // The general problem looks like this
+                // GHIJKLM...ABCDEF - before any swaps
+                // ABCDEFM...GHIJKL - after 1 pass of swaps
+                // ABCDEFGHIJM...KL - swap until the left edge reaches the temp store
+                //                  - then restart the algorithm with a new (smaller) store
+                // Sometimes the temp store is reached when the right edge is at the end
+                // of the buffer - this means we've hit the right order with fewer swaps!
+                // E.g
+                // EF..ABCD
+                // ABCDEF.. - after four only swaps we've finished
+                while left_edge < len && right_edge != cap {
+                    let mut right_offset = 0;
+                    for i in left_edge..right_edge {
+                        right_offset = (i - left_edge) % (cap - right_edge);
+                        let src: isize = (right_edge + right_offset) as isize;
+                        ptr::swap(buf.add(i), buf.offset(src));
+                    }
+                    let n_ops = right_edge - left_edge;
+                    left_edge += n_ops;
+                    right_edge += right_offset + 1;
+                }
+
+                self.tail = 0;
+                self.head = len;
+            }
+        }
+
+        let tail = self.tail;
+        let head = self.head;
+        unsafe { &mut self.buffer_as_mut_slice()[tail..head] }
+    }
+
     /// Rotates the double-ended queue `mid` places to the left.
     ///
     /// Equivalently,
@@ -2803,63 +2951,16 @@ impl<T> From<VecDeque<T>> for Vec<T> {
     /// assert_eq!(vec, [8, 9, 1, 2, 3, 4]);
     /// assert_eq!(vec.as_ptr(), ptr);
     /// ```
-    fn from(other: VecDeque<T>) -> Self {
+    fn from(mut other: VecDeque<T>) -> Self {
+        other.make_contiguous();
+
         unsafe {
             let buf = other.buf.ptr();
             let len = other.len();
-            let tail = other.tail;
-            let head = other.head;
             let cap = other.cap();
 
-            // Need to move the ring to the front of the buffer, as vec will expect this.
-            if other.is_contiguous() {
-                ptr::copy(buf.add(tail), buf, len);
-            } else {
-                if (tail - head) >= cmp::min(cap - tail, head) {
-                    // There is enough free space in the centre for the shortest block so we can
-                    // do this in at most three copy moves.
-                    if (cap - tail) > head {
-                        // right hand block is the long one; move that enough for the left
-                        ptr::copy(buf.add(tail), buf.add(tail - head), cap - tail);
-                        // copy left in the end
-                        ptr::copy(buf, buf.add(cap - head), head);
-                        // shift the new thing to the start
-                        ptr::copy(buf.add(tail - head), buf, len);
-                    } else {
-                        // left hand block is the long one, we can do it in two!
-                        ptr::copy(buf, buf.add(cap - tail), head);
-                        ptr::copy(buf.add(tail), buf, cap - tail);
-                    }
-                } else {
-                    // Need to use N swaps to move the ring
-                    // We can use the space at the end of the ring as a temp store
-
-                    let mut left_edge: usize = 0;
-                    let mut right_edge: usize = tail;
-
-                    // The general problem looks like this
-                    // GHIJKLM...ABCDEF - before any swaps
-                    // ABCDEFM...GHIJKL - after 1 pass of swaps
-                    // ABCDEFGHIJM...KL - swap until the left edge reaches the temp store
-                    //                  - then restart the algorithm with a new (smaller) store
-                    // Sometimes the temp store is reached when the right edge is at the end
-                    // of the buffer - this means we've hit the right order with fewer swaps!
-                    // E.g
-                    // EF..ABCD
-                    // ABCDEF.. - after four only swaps we've finished
-
-                    while left_edge < len && right_edge != cap {
-                        let mut right_offset = 0;
-                        for i in left_edge..right_edge {
-                            right_offset = (i - left_edge) % (cap - right_edge);
-                            let src: isize = (right_edge + right_offset) as isize;
-                            ptr::swap(buf.add(i), buf.offset(src));
-                        }
-                        let n_ops = right_edge - left_edge;
-                        left_edge += n_ops;
-                        right_edge += right_offset + 1;
-                    }
-                }
+            if other.head != 0 {
+                ptr::copy(buf.add(other.tail), buf, len);
             }
             let out = Vec::from_raw_parts(buf, len, cap);
             mem::forget(other);
diff --git a/src/liballoc/collections/vec_deque/tests.rs b/src/liballoc/collections/vec_deque/tests.rs
index f2ce5b1d15d..8ef5ec78e05 100644
--- a/src/liballoc/collections/vec_deque/tests.rs
+++ b/src/liballoc/collections/vec_deque/tests.rs
@@ -1,6 +1,6 @@
 use super::*;
 
-use ::test;
+use test;
 
 #[bench]
 #[cfg_attr(miri, ignore)] // Miri does not support benchmarks
@@ -131,6 +131,87 @@ fn test_insert() {
 }
 
 #[test]
+fn make_contiguous_big_tail() {
+    let mut tester = VecDeque::with_capacity(15);
+
+    for i in 0..3 {
+        tester.push_back(i);
+    }
+
+    for i in 3..10 {
+        tester.push_front(i);
+    }
+
+    // 012......9876543
+    assert_eq!(tester.capacity(), 15);
+    assert_eq!((&[9, 8, 7, 6, 5, 4, 3] as &[_], &[0, 1, 2] as &[_]), tester.as_slices());
+
+    let expected_start = tester.head;
+    tester.make_contiguous();
+    assert_eq!(tester.tail, expected_start);
+    assert_eq!((&[9, 8, 7, 6, 5, 4, 3, 0, 1, 2] as &[_], &[] as &[_]), tester.as_slices());
+}
+
+#[test]
+fn make_contiguous_big_head() {
+    let mut tester = VecDeque::with_capacity(15);
+
+    for i in 0..8 {
+        tester.push_back(i);
+    }
+
+    for i in 8..10 {
+        tester.push_front(i);
+    }
+
+    // 01234567......98
+    let expected_start = 0;
+    tester.make_contiguous();
+    assert_eq!(tester.tail, expected_start);
+    assert_eq!((&[9, 8, 0, 1, 2, 3, 4, 5, 6, 7] as &[_], &[] as &[_]), tester.as_slices());
+}
+
+#[test]
+fn make_contiguous_small_free() {
+    let mut tester = VecDeque::with_capacity(15);
+
+    for i in 'A' as u8..'I' as u8 {
+        tester.push_back(i as char);
+    }
+
+    for i in 'I' as u8..'N' as u8 {
+        tester.push_front(i as char);
+    }
+
+    // ABCDEFGH...MLKJI
+    let expected_start = 0;
+    tester.make_contiguous();
+    assert_eq!(tester.tail, expected_start);
+    assert_eq!(
+        (&['M', 'L', 'K', 'J', 'I', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] as &[_], &[] as &[_]),
+        tester.as_slices()
+    );
+
+    tester.clear();
+    for i in 'I' as u8..'N' as u8 {
+        tester.push_back(i as char);
+    }
+
+    for i in 'A' as u8..'I' as u8 {
+        tester.push_front(i as char);
+    }
+
+    // IJKLM...HGFEDCBA
+    let expected_start = 0;
+    tester.make_contiguous();
+    assert_eq!(tester.tail, expected_start);
+    assert_eq!(
+        (&['H', 'G', 'F', 'E', 'D', 'C', 'B', 'A', 'I', 'J', 'K', 'L', 'M'] as &[_], &[] as &[_]),
+        tester.as_slices()
+    );
+}
+
+#[test]
 fn test_remove() {
     // This test checks that every single combination of tail position, length, and
     // removal position is tested. Capacity 15 should be large enough to cover every case.
diff --git a/src/librustc_error_codes/error_codes/E0466.md b/src/librustc_error_codes/error_codes/E0466.md
index 443b7bae134..7aefedbc087 100644
--- a/src/librustc_error_codes/error_codes/E0466.md
+++ b/src/librustc_error_codes/error_codes/E0466.md
@@ -1,4 +1,4 @@
-Macro import declarations were malformed.
+Macro import declaration was malformed.
 
 Erroneous code examples:
 
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 8e004e45b7a..f1ddf3c635f 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -274,19 +274,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         _memory_extra: &(),
         _alloc_id: AllocId,
         allocation: &Allocation<Self::PointerTag, Self::AllocExtra>,
-        static_def_id: Option<DefId>,
+        _static_def_id: Option<DefId>,
         is_write: bool,
     ) -> InterpResult<'tcx> {
         if is_write {
             throw_machine_stop_str!("can't write to global");
         }
-        // If the static allocation is mutable or if it has relocations (it may be legal to mutate
-        // the memory behind that in the future), then we can't const prop it.
+        // If the static allocation is mutable, then we can't const prop it as its content
+        // might be different at runtime.
         if allocation.mutability == Mutability::Mut {
-            throw_machine_stop_str!("can't eval mutable globals in ConstProp");
-        }
-        if static_def_id.is_some() && allocation.relocations().len() > 0 {
-            throw_machine_stop_str!("can't eval statics with pointers in ConstProp");
+            throw_machine_stop_str!("can't access mutable globals in ConstProp");
         }
 
         Ok(())
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index d154de35043..f9e9a07914d 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -13,6 +13,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
 use rustc_target::spec::TargetTriple;
+use std::collections::HashMap;
 use std::env;
 use std::io::{self, Write};
 use std::panic;
@@ -190,10 +191,23 @@ enum TestFailure {
     UnexpectedRunPass,
 }
 
+enum DirState {
+    Temp(tempfile::TempDir),
+    Perm(PathBuf),
+}
+
+impl DirState {
+    fn path(&self) -> &std::path::Path {
+        match self {
+            DirState::Temp(t) => t.path(),
+            DirState::Perm(p) => p.as_path(),
+        }
+    }
+}
+
 fn run_test(
     test: &str,
     cratename: &str,
-    filename: &FileName,
     line: usize,
     options: Options,
     should_panic: bool,
@@ -206,47 +220,11 @@ fn run_test(
     mut error_codes: Vec<String>,
     opts: &TestOptions,
     edition: Edition,
+    outdir: DirState,
+    path: PathBuf,
 ) -> Result<(), TestFailure> {
     let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts, edition);
 
-    // FIXME(#44940): if doctests ever support path remapping, then this filename
-    // needs to be the result of `SourceMap::span_to_unmapped_path`.
-    let path = match filename {
-        FileName::Real(path) => path.clone(),
-        _ => PathBuf::from(r"doctest.rs"),
-    };
-
-    enum DirState {
-        Temp(tempfile::TempDir),
-        Perm(PathBuf),
-    }
-
-    impl DirState {
-        fn path(&self) -> &std::path::Path {
-            match self {
-                DirState::Temp(t) => t.path(),
-                DirState::Perm(p) => p.as_path(),
-            }
-        }
-    }
-
-    let outdir = if let Some(mut path) = options.persist_doctests {
-        path.push(format!(
-            "{}_{}",
-            filename.to_string().rsplit('/').next().unwrap().replace(".", "_"),
-            line
-        ));
-        std::fs::create_dir_all(&path).expect("Couldn't create directory for doctest executables");
-
-        DirState::Perm(path)
-    } else {
-        DirState::Temp(
-            TempFileBuilder::new()
-                .prefix("rustdoctest")
-                .tempdir()
-                .expect("rustdoc needs a tempdir"),
-        )
-    };
     let output_file = outdir.path().join("rust_out");
 
     let rustc_binary = options
@@ -639,6 +617,7 @@ pub struct Collector {
     position: Span,
     source_map: Option<Lrc<SourceMap>>,
     filename: Option<PathBuf>,
+    visited_tests: HashMap<(String, usize), usize>,
 }
 
 impl Collector {
@@ -662,6 +641,7 @@ impl Collector {
             position: DUMMY_SP,
             source_map,
             filename,
+            visited_tests: HashMap::new(),
         }
     }
 
@@ -705,6 +685,48 @@ impl Tester for Collector {
         let target = self.options.target.clone();
         let target_str = target.to_string();
 
+        // FIXME(#44940): if doctests ever support path remapping, then this filename
+        // needs to be the result of `SourceMap::span_to_unmapped_path`.
+        let path = match &filename {
+            FileName::Real(path) => path.clone(),
+            _ => PathBuf::from(r"doctest.rs"),
+        };
+
+        let outdir = if let Some(mut path) = options.persist_doctests.clone() {
+            // For example `module/file.rs` would become `module_file_rs`
+            let folder_name = filename
+                .to_string()
+                .chars()
+                .map(|c| if c == '/' || c == '.' { '_' } else { c })
+                .collect::<String>();
+
+            path.push(format!(
+                "{name}_{line}_{number}",
+                name = folder_name,
+                number = {
+                    // Increases the current test number, if this file already
+                    // exists or it creates a new entry with a test number of 0.
+                    self.visited_tests
+                        .entry((folder_name.clone(), line))
+                        .and_modify(|v| *v += 1)
+                        .or_insert(0)
+                },
+                line = line,
+            ));
+
+            std::fs::create_dir_all(&path)
+                .expect("Couldn't create directory for doctest executables");
+
+            DirState::Perm(path)
+        } else {
+            DirState::Temp(
+                TempFileBuilder::new()
+                    .prefix("rustdoctest")
+                    .tempdir()
+                    .expect("rustdoc needs a tempdir"),
+            )
+        };
+
         debug!("creating test {}: {}", name, test);
         self.tests.push(testing::TestDescAndFn {
             desc: testing::TestDesc {
@@ -723,7 +745,6 @@ impl Tester for Collector {
                 let res = run_test(
                     &test,
                     &cratename,
-                    &filename,
                     line,
                     options,
                     config.should_panic,
@@ -736,6 +757,8 @@ impl Tester for Collector {
                     config.error_codes,
                     &opts,
                     edition,
+                    outdir,
+                    path,
                 );
 
                 if let Err(err) = res {
diff --git a/src/test/ui/intrinsics/intrinsic-alignment.rs b/src/test/ui/intrinsics/intrinsic-alignment.rs
index 02e3139d294..896651361be 100644
--- a/src/test/ui/intrinsics/intrinsic-alignment.rs
+++ b/src/test/ui/intrinsics/intrinsic-alignment.rs
@@ -56,16 +56,6 @@ mod m {
 #[cfg(target_os = "windows")]
 mod m {
     #[main]
-    #[cfg(target_arch = "x86")]
-    pub fn main() {
-        unsafe {
-            assert_eq!(::rusti::pref_align_of::<u64>(), 8);
-            assert_eq!(::rusti::min_align_of::<u64>(), 8);
-        }
-    }
-
-    #[main]
-    #[cfg(target_arch = "x86_64")]
     pub fn main() {
         unsafe {
             assert_eq!(::rusti::pref_align_of::<u64>(), 8);
diff --git a/src/test/ui/structs-enums/rec-align-u64.rs b/src/test/ui/structs-enums/rec-align-u64.rs
index 680a690ba34..b06e204d31b 100644
--- a/src/test/ui/structs-enums/rec-align-u64.rs
+++ b/src/test/ui/structs-enums/rec-align-u64.rs
@@ -67,13 +67,6 @@ mod m {
 
 #[cfg(target_os = "windows")]
 mod m {
-    #[cfg(target_arch = "x86")]
-    pub mod m {
-        pub fn align() -> usize { 8 }
-        pub fn size() -> usize { 16 }
-    }
-
-    #[cfg(target_arch = "x86_64")]
     pub mod m {
         pub fn align() -> usize { 8 }
         pub fn size() -> usize { 16 }