about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-29 16:08:35 +0000
committerbors <bors@rust-lang.org>2022-01-29 16:08:35 +0000
commita00e130dae74a213338e2b095ec855156d8f3d8a (patch)
treed8afd415e451e7e736cf2ca49902c67d75207744
parentd08e816333281b0c0fb5a99c2c15d8084312e41a (diff)
parentd62b414b808be3d75204d6b15cf8547643703109 (diff)
downloadrust-a00e130dae74a213338e2b095ec855156d8f3d8a.tar.gz
rust-a00e130dae74a213338e2b095ec855156d8f3d8a.zip
Auto merge of #93457 - matthiaskrgr:rollup-e43ry1l, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #88205 (Add Explanation For Error E0772)
 - #92274 (Add `intrinsics::const_deallocate`)
 - #93236 (Make `NonNull::new` `const`)
 - #93299 (Fix dot separator when there is no source link)
 - #93410 (kmc-solid: Implement `net::FileDesc::duplicate`)
 - #93424 (fix nit)
 - #93431 (remove unused `jemallocator` crate)
 - #93453 (Add GUI theme change test)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock11
-rw-r--r--compiler/rustc/Cargo.toml6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs27
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0772.md89
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs5
-rw-r--r--library/core/src/intrinsics.rs23
-rw-r--r--library/core/src/ptr/non_null.rs3
-rw-r--r--library/core/tests/intrinsics.rs22
-rw-r--r--library/core/tests/lib.rs3
-rw-r--r--library/core/tests/ptr.rs15
-rw-r--r--library/std/src/sys/solid/abi/sockets.rs3
-rw-r--r--library/std/src/sys/solid/net.rs2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile2
-rw-r--r--src/librustdoc/html/render/mod.rs7
-rw-r--r--src/test/rustdoc-gui/theme-change.goml16
-rw-r--r--src/test/rustdoc/version-separator-without-source.rs23
-rw-r--r--src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs3
-rw-r--r--src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr2
-rw-r--r--src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs16
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs36
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs22
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr15
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs13
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr9
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs29
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr27
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs17
-rw-r--r--src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr3
-rw-r--r--src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr3
33 files changed, 437 insertions, 30 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 05b090b8576..b05351a1e96 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3319,7 +3319,6 @@ dependencies = [
  "rustc_codegen_ssa",
  "rustc_driver",
  "tikv-jemalloc-sys",
- "tikv-jemallocator",
 ]
 
 [[package]]
@@ -5165,16 +5164,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "tikv-jemallocator"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c14a5a604eb8715bc5785018a37d00739b180bcf609916ddf4393d33d49ccdf"
-dependencies = [
- "libc",
- "tikv-jemalloc-sys",
-]
-
-[[package]]
 name = "time"
 version = "0.1.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index 277cf0f51d3..696c003a587 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -15,11 +15,7 @@ version = '0.4.0'
 optional = true
 features = ['unprefixed_malloc_on_supported_platforms']
 
-[dependencies.tikv-jemallocator]
-version = '0.4.0'
-optional = true
-
 [features]
-jemalloc = ['tikv-jemalloc-sys', 'tikv-jemallocator']
+jemalloc = ['tikv-jemalloc-sys']
 llvm = ['rustc_driver/llvm']
 max_level_info = ['rustc_driver/max_level_info']
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 3657f80c2de..c654232c10a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -369,6 +369,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
+            sym::const_allocate => {
+                // returns a null pointer at runtime.
+                bx.const_null(bx.type_i8p())
+            }
+
+            sym::const_deallocate => {
+                // nop at runtime.
+                return;
+            }
+
             // This requires that atomic intrinsics follow a specific naming pattern:
             // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
             name if name_str.starts_with("atomic_") => {
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 30e9cbe4403..89717b75f12 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -347,6 +347,33 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 )?;
                 ecx.write_pointer(ptr, dest)?;
             }
+            sym::const_deallocate => {
+                let ptr = ecx.read_pointer(&args[0])?;
+                let size = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
+                let align = ecx.read_scalar(&args[2])?.to_machine_usize(ecx)?;
+
+                let size = Size::from_bytes(size);
+                let align = match Align::from_bytes(align) {
+                    Ok(a) => a,
+                    Err(err) => throw_ub_format!("align has to be a power of 2, {}", err),
+                };
+
+                // If an allocation is created in an another const,
+                // we don't deallocate it.
+                let (alloc_id, _, _) = ecx.memory.ptr_get_alloc(ptr)?;
+                let is_allocated_in_another_const = matches!(
+                    ecx.tcx.get_global_alloc(alloc_id),
+                    Some(interpret::GlobalAlloc::Memory(_))
+                );
+
+                if !is_allocated_in_another_const {
+                    ecx.memory.deallocate(
+                        ptr,
+                        Some((size, align)),
+                        interpret::MemoryKind::Machine(MemoryKind::Heap),
+                    )?;
+                }
+            }
             _ => {
                 return Err(ConstEvalErrKind::NeedsRfc(format!(
                     "calling intrinsic `{}`",
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index d4b12d00f1f..c401f65edda 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -472,6 +472,7 @@ E0768: include_str!("./error_codes/E0768.md"),
 E0769: include_str!("./error_codes/E0769.md"),
 E0770: include_str!("./error_codes/E0770.md"),
 E0771: include_str!("./error_codes/E0771.md"),
+E0772: include_str!("./error_codes/E0772.md"),
 E0773: include_str!("./error_codes/E0773.md"),
 E0774: include_str!("./error_codes/E0774.md"),
 E0775: include_str!("./error_codes/E0775.md"),
@@ -642,5 +643,4 @@ E0787: include_str!("./error_codes/E0787.md"),
 //  E0723, // unstable feature in `const` context
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
-    E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0772.md b/compiler/rustc_error_codes/src/error_codes/E0772.md
new file mode 100644
index 00000000000..262e52351ef
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0772.md
@@ -0,0 +1,89 @@
+A trait object has some specific lifetime `'1`, but it was used in a way that
+requires it to have a `'static` lifetime.
+
+Example of erroneous code:
+
+```compile_fail,E0772
+trait BooleanLike {}
+trait Person {}
+
+impl BooleanLike for bool {}
+
+impl dyn Person {
+    fn is_cool(&self) -> bool {
+        // hey you, you're pretty cool
+        true
+    }
+}
+
+fn get_is_cool<'p>(person: &'p dyn Person) -> impl BooleanLike {
+    // error: `person` has an anonymous lifetime `'p` but calling
+    //        `print_cool_fn` introduces an implicit `'static` lifetime
+    //        requirement
+    person.is_cool()
+}
+```
+
+The trait object `person` in the function `get_is_cool`, while already being
+behind a reference with lifetime `'p`, also has it's own implicit lifetime,
+`'2`.
+
+Lifetime `'2` represents the data the trait object might hold inside, for
+example:
+
+```
+trait MyTrait {}
+
+struct MyStruct<'a>(&'a i32);
+
+impl<'a> MyTrait for MyStruct<'a> {}
+```
+
+With this scenario, if a trait object of `dyn MyTrait + '2` was made from
+`MyStruct<'a>`, `'a` must live as long, if not longer than `'2`. This allows the
+trait object's internal data to be accessed safely from any trait methods. This
+rule also goes for any lifetime any struct made into a trait object may have.
+
+In the implementation for `dyn Person`, the `'2` lifetime representing the
+internal data was ommitted, meaning that the compiler inferred the lifetime
+`'static`. As a result, the implementation's `is_cool` is inferred by the
+compiler to look like this:
+
+```
+# trait Person {}
+#
+# impl dyn Person {
+fn is_cool<'a>(self: &'a (dyn Person + 'static)) -> bool {unimplemented!()}
+# }
+```
+
+While the `get_is_cool` function is inferred to look like this:
+
+```
+# trait Person {}
+# trait BooleanLike {}
+#
+fn get_is_cool<'p, R: BooleanLike>(person: &'p (dyn Person + 'p)) -> R {
+    unimplemented!()
+}
+```
+
+Which brings us to the core of the problem; the assignment of type
+`&'_ (dyn Person + '_)` to type `&'_ (dyn Person + 'static)` is impossible.
+
+Fixing it is as simple as being generic over lifetime `'2`, as to prevent the
+compiler from inferring it as `'static`:
+
+```
+# trait Person {}
+#
+impl<'d> dyn Person + 'd {/* ... */}
+
+// This works too, and is more elegant:
+//impl dyn Person + '_ {/* ... */}
+```
+
+See the [Rust Reference on Trait Object Lifetime Bounds][trait-objects] for
+more information on trait object lifetimes.
+
+[trait-object-lifetime-bounds]: https://doc.rust-lang.org/reference/types/trait-object.html#trait-object-lifetime-bounds
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 20db25f7899..f70fde2a040 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1810,7 +1810,7 @@ impl<'tcx> TyS<'tcx> {
     pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
             Array(ty, _) | Slice(ty) => ty,
-            Str => tcx.mk_mach_uint(ty::UintTy::U8),
+            Str => tcx.types.u8,
             _ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
         }
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d99bdd3bdd5..9fba9c77d07 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -461,6 +461,7 @@ symbols! {
         const_async_blocks,
         const_compare_raw_pointers,
         const_constructor,
+        const_deallocate,
         const_eval_limit,
         const_eval_select,
         const_eval_select_ct,
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 4c612ed5be5..74f6f50d412 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -297,6 +297,11 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::const_allocate => {
                 (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8))
             }
+            sym::const_deallocate => (
+                0,
+                vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize],
+                tcx.mk_unit(),
+            ),
 
             sym::ptr_offset_from => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 9781dc320ed..b5228397f0a 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1914,10 +1914,31 @@ extern "rust-intrinsic" {
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
 
-    /// Allocate at compile time. Should not be called at runtime.
+    /// Allocates a block of memory at compile time.
+    /// At runtime, just returns a null pointer.
+    ///
+    /// # Safety
+    ///
+    /// - The `align` argument must be a power of two.
+    ///    - At compile time, a compile error occurs if this constraint is violated.
+    ///    - At runtime, it is not checked.
     #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
     pub fn const_allocate(size: usize, align: usize) -> *mut u8;
 
+    /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
+    /// At runtime, does nothing.
+    ///
+    /// # Safety
+    ///
+    /// - The `align` argument must be a power of two.
+    ///    - At compile time, a compile error occurs if this constraint is violated.
+    ///    - At runtime, it is not checked.
+    /// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it.
+    /// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it.
+    #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
+    #[cfg(not(bootstrap))]
+    pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);
+
     /// Determines whether the raw bytes of the two values are equal.
     ///
     /// This is particularly handy for arrays, since it allows things like just
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 3a7e99faccf..3f5d3f62c96 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -211,8 +211,9 @@ impl<T: ?Sized> NonNull<T> {
     /// }
     /// ```
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")]
     #[inline]
-    pub fn new(ptr: *mut T) -> Option<Self> {
+    pub const fn new(ptr: *mut T) -> Option<Self> {
         if !ptr.is_null() {
             // SAFETY: The pointer is already checked and is not null
             Some(unsafe { Self::new_unchecked(ptr) })
diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs
index 7a2e4e29065..df940de4795 100644
--- a/library/core/tests/intrinsics.rs
+++ b/library/core/tests/intrinsics.rs
@@ -80,3 +80,25 @@ fn test_hints_in_const_contexts() {
         assert!(42u32 == core::hint::black_box(42u32));
     }
 }
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_const_allocate_at_runtime() {
+    use core::intrinsics::const_allocate;
+    unsafe {
+        assert!(const_allocate(4, 4).is_null());
+    }
+}
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_const_deallocate_at_runtime() {
+    use core::intrinsics::const_deallocate;
+    const X: &u32 = &42u32;
+    let x = &0u32;
+    unsafe {
+        const_deallocate(X as *const _ as *mut u8, 4, 4); // nop
+        const_deallocate(x as *const _ as *mut u8, 4, 4); // nop
+        const_deallocate(core::ptr::null_mut(), 1, 1); // nop
+    }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 841c114063d..a2bef2012cf 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -13,10 +13,13 @@
 #![feature(const_bool_to_option)]
 #![feature(const_cell_into_inner)]
 #![feature(const_convert)]
+#![feature(const_heap)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_assume_init)]
 #![feature(const_maybe_uninit_assume_init_read)]
+#![feature(const_nonnull_new)]
 #![feature(const_num_from_num)]
+#![feature(const_ptr_as_ref)]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_ptr_offset)]
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index b9c0d75b702..bbfd2d64dda 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -275,6 +275,21 @@ fn test_unsized_nonnull() {
 }
 
 #[test]
+fn test_const_nonnull_new() {
+    const {
+        assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none());
+
+        let value = &mut 0u32;
+        let mut ptr = NonNull::new(value).unwrap();
+        unsafe { *ptr.as_mut() = 42 };
+
+        let reference = unsafe { &*ptr.as_ref() };
+        assert!(*reference == *value);
+        assert!(*reference == 42);
+    };
+}
+
+#[test]
 #[allow(warnings)]
 // Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
 // ABI, or even point to an actual executable code, because the function itself is never invoked.
diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs
index 7c21d0dd25e..eb06a6dd927 100644
--- a/library/std/src/sys/solid/abi/sockets.rs
+++ b/library/std/src/sys/solid/abi/sockets.rs
@@ -175,6 +175,9 @@ extern "C" {
     #[link_name = "SOLID_NET_Close"]
     pub fn close(s: c_int) -> c_int;
 
+    #[link_name = "SOLID_NET_Dup"]
+    pub fn dup(s: c_int) -> c_int;
+
     #[link_name = "SOLID_NET_GetPeerName"]
     pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
 
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index 63ba6341c79..c91ecce4d72 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -107,7 +107,7 @@ impl FileDesc {
     }
 
     fn duplicate(&self) -> io::Result<FileDesc> {
-        super::unsupported()
+        cvt(unsafe { netc::dup(self.fd) }).map(Self::new)
     }
 }
 
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index d4701a25614..c547e12f5b6 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # https://github.com/puppeteer/puppeteer/issues/375
 #
 # We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.5.3 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.5.8 --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 32e4a829184..0b6faa4b13e 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1676,11 +1676,12 @@ fn render_rightside(
         containing_item.stable_since(tcx),
         const_stable_since,
     );
-    if has_stability {
+    let mut tmp_buf = Buffer::empty_from(w);
+    write_srclink(cx, item, &mut tmp_buf);
+    if has_stability && !tmp_buf.is_empty() {
         w.write_str(" · ");
     }
-
-    write_srclink(cx, item, w);
+    w.push_buffer(tmp_buf);
     w.write_str("</div>");
 }
 
diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml
index 60d089ffa37..73edee64e43 100644
--- a/src/test/rustdoc-gui/theme-change.goml
+++ b/src/test/rustdoc-gui/theme-change.goml
@@ -9,3 +9,19 @@ click: "#theme-choices > button:last-child"
 wait-for: 500
 // should be the light theme so let's check the color
 assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+
+goto: file://|DOC_PATH|/settings.html
+click: "#theme-light"
+wait-for: 500
+assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
+
+click: "#theme-dark"
+wait-for: 500
+assert-css: ("body", { "background-color": "rgb(53, 53, 53)" })
+assert-local-storage: { "rustdoc-theme": "dark" }
+
+click: "#theme-ayu"
+wait-for: 500
+assert-css: ("body", { "background-color": "rgb(15, 20, 25)" })
+assert-local-storage: { "rustdoc-theme": "ayu" }
diff --git a/src/test/rustdoc/version-separator-without-source.rs b/src/test/rustdoc/version-separator-without-source.rs
new file mode 100644
index 00000000000..bffe5030a84
--- /dev/null
+++ b/src/test/rustdoc/version-separator-without-source.rs
@@ -0,0 +1,23 @@
+#![doc(html_no_source)]
+#![feature(staged_api)]
+#![stable(feature = "bar", since = "1.0")]
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "bar", since = "1.0")]
+pub fn foo() {}
+
+// @has foo/struct.Bar.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "bar", since = "1.0")]
+pub struct Bar;
+
+impl Bar {
+    // @has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0'
+    // @!has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
+    #[stable(feature = "foobar", since = "2.0")]
+    pub fn bar() {}
+}
diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
index 1a1d9a6d540..ac9e8b64b48 100644
--- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
+++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
@@ -6,11 +6,10 @@ use std::intrinsics;
 const FOO: i32 = foo();
 const fn foo() -> i32 {
     unsafe {
-        let _ = intrinsics::const_allocate(4, 3) as * mut i32;
+        let _ = intrinsics::const_allocate(4, 3) as *mut i32;
         //~^ error: evaluation of constant value failed
     }
     1
-
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
index 74fb65ca1a6..2628a78455c 100644
--- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
+++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 LL | const FOO: i32 = foo();
    |                  ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18
 ...
-LL |         let _ = intrinsics::const_allocate(4, 3) as * mut i32;
+LL |         let _ = intrinsics::const_allocate(4, 3) as *mut i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                 |
    |                 align has to be a power of 2, `3` is not a power of 2
diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs
new file mode 100644
index 00000000000..407e69d41a0
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(inline_const)]
+
+use std::intrinsics;
+
+struct ZST;
+
+fn main() {
+    const {
+        unsafe {
+            let _ = intrinsics::const_allocate(0, 0) as *mut ZST;
+        }
+    }
+}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs
new file mode 100644
index 00000000000..aac90cd54cc
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs
@@ -0,0 +1,36 @@
+// run-pass
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(const_mut_refs)]
+
+use std::intrinsics;
+
+const _X: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+};
+
+const Y: &u32 = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4) as *mut u32;
+    *ptr = 42;
+    &*ptr
+};
+
+const Z: &u32 = &42;
+
+const _Z: () = unsafe {
+    let ptr1 = Y as *const _ as *mut u8;
+    intrinsics::const_deallocate(ptr1, 4, 4); // nop
+    intrinsics::const_deallocate(ptr1, 2, 4); // nop
+    intrinsics::const_deallocate(ptr1, 4, 2); // nop
+
+    let ptr2 = Z as *const _ as *mut u8;
+    intrinsics::const_deallocate(ptr2, 4, 4); // nop
+    intrinsics::const_deallocate(ptr2, 2, 4); // nop
+    intrinsics::const_deallocate(ptr2, 4, 2); // nop
+};
+
+fn main() {
+    assert_eq!(*Y, 42);
+    assert_eq!(*Z, 42);
+}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs
new file mode 100644
index 00000000000..b6d89a58dce
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs
@@ -0,0 +1,22 @@
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(const_mut_refs)]
+
+use std::intrinsics;
+
+const _X: &'static u8 = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+    &*ptr
+    //~^ error: evaluation of constant value failed
+};
+
+const _Y: u8 = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    let reference = &*ptr;
+    intrinsics::const_deallocate(ptr, 4, 4);
+    *reference
+    //~^ error: evaluation of constant value failed
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
new file mode 100644
index 00000000000..4eb1c42e1f7
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
@@ -0,0 +1,15 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_dangling.rs:10:5
+   |
+LL |     &*ptr
+   |     ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_dangling.rs:18:5
+   |
+LL |     *reference
+   |     ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs
new file mode 100644
index 00000000000..4010b476990
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs
@@ -0,0 +1,13 @@
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+
+use std::intrinsics;
+
+const _X: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+    //~^ error: evaluation of constant value failed
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr
new file mode 100644
index 00000000000..8177a08504b
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_duplicate.rs:9:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 4, 4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs
new file mode 100644
index 00000000000..031d70fdc88
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs
@@ -0,0 +1,29 @@
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+
+use std::intrinsics;
+
+const _X: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 2);
+    //~^ error: evaluation of constant value failed
+};
+const _Y: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 2, 4);
+    //~^ error: evaluation of constant value failed
+};
+
+const _Z: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 3, 4);
+    //~^ error: evaluation of constant value failed
+};
+
+const _W: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 3);
+    //~^ error: evaluation of constant value failed
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr
new file mode 100644
index 00000000000..650b409b190
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 4, 2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc2 has size 4 and alignment 4, but gave size 4 and alignment 2
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 2, 4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc4 has size 4 and alignment 4, but gave size 2 and alignment 4
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 3, 4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc6 has size 4 and alignment 4, but gave size 3 and alignment 4
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 4, 3);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ align has to be a power of 2, `3` is not a power of 2
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs
new file mode 100644
index 00000000000..84fb4d2ea87
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(inline_const)]
+
+use std::intrinsics;
+
+fn main() {
+    const {
+        unsafe {
+            let ptr1 = intrinsics::const_allocate(0, 0);
+            let ptr2 = intrinsics::const_allocate(0, 0);
+            intrinsics::const_deallocate(ptr1, 0, 0);
+            intrinsics::const_deallocate(ptr2, 0, 0);
+        }
+    }
+}
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
index 63d291ed7cd..b125eacfb6c 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
@@ -38,4 +38,5 @@ LL |     impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0515`.
+Some errors have detailed explanations: E0515, E0772.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
index 55a1bbf18ab..ed094c1365c 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
@@ -131,4 +131,5 @@ LL |     impl MyTrait for Box<dyn ObjectTrait + '_> {
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0759`.
+Some errors have detailed explanations: E0759, E0772.
+For more information about an error, try `rustc --explain E0759`.