diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile
index 9eaffbf83eb4e..01d6fce34186a 100644
--- a/src/ci/docker/asmjs/Dockerfile
+++ b/src/ci/docker/asmjs/Dockerfile
@@ -37,3 +37,11 @@ ENV SCRIPT python2.7 ../x.py test --target $TARGETS \
   src/libstd \
   src/liballoc \
   src/libcore
+
+# Debug assertions in rustc are largely covered by other builders, and LLVM
+# assertions cause this builder to slow down by quite a large amount and don't
+# buy us a huge amount over other builders (not sure if we've ever seen an
+# asmjs-specific backend assertion trip), so disable assertions for these
+# tests.
+ENV NO_LLVM_ASSERTIONS=1
+ENV NO_DEBUG_ASSERTIONS=1
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 4ced860948bee..c5247e134c86a 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -1,10 +1,10 @@
 //! Types that pin data to its location in memory.
 //!
-//! It is sometimes useful to have objects that are guaranteed to not move,
+//! It is sometimes useful to have objects that are guaranteed not to move,
 //! in the sense that their placement in memory does not change, and can thus be relied upon.
 //! A prime example of such a scenario would be building self-referential structs,
-//! since moving an object with pointers to itself will invalidate them,
-//! which could cause undefined behavior.
+//! as moving an object with pointers to itself will invalidate them, which could cause undefined
+//! behavior.
 //!
 //! A [`Pin
`] ensures that the pointee of any pointer type `P` has a stable location in memory,
 //! meaning it cannot be moved elsewhere and its memory cannot be deallocated
@@ -15,9 +15,10 @@
 //! moving the values they contain: you can move out of a `Box`, or you can use [`mem::swap`].
 //! [`Pin`] wraps a pointer type `P`, so `Pin>` functions much like a regular `Box`:
 //! when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated.
-//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin`] does not let clients
+//! Similarly, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin
`] does not let clients
 //! actually obtain a `Box` or `&mut T` to pinned data, which implies that you cannot use
 //! operations such as [`mem::swap`]:
+//!
 //! ```
 //! use std::pin::Pin;
 //! fn swap_pins(x: Pin<&mut T>, y: Pin<&mut T>) {
@@ -39,19 +40,19 @@
 //! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin>` is
 //! an owned pointer to a pinned `T`, and a `Pin>` is a reference-counted
 //! pointer to a pinned `T`.
-//! For correctness, [`Pin`] relies on the [`Deref`] and [`DerefMut`] implementations
-//! to not move out of their `self` parameter, and to only ever return a pointer
-//! to pinned data when they are called on a pinned pointer.
+//! For correctness, [`Pin
`] relies on the implementations of [`Deref`] and
+//! [`DerefMut`] not to move out of their `self` parameter, and only ever to
+//! return a pointer to pinned data when they are called on a pinned pointer.
 //!
 //! # `Unpin`
 //!
-//! However, these restrictions are usually not necessary. Many types are always freely
-//! movable, even when pinned, because they do not rely on having a stable address.
-//! This includes all the basic types (like `bool`, `i32`, references)
-//! as well as types consisting solely of these types.
-//! Types that do not care about pinning implement the [`Unpin`] auto-trait, which
-//! cancels the effect of [`Pin
`]. For `T: Unpin`, `Pin>` and `Box` function
-//! identically, as do `Pin<&mut T>` and `&mut T`.
+//! Many types are always freely movable, even when pinned, because they do not
+//! rely on having a stable address. This includes all the basic types (like
+//! `bool`, `i32`, and references) as well as types consisting solely of these
+//! types. Types that do not care about pinning implement the [`Unpin`]
+//! auto-trait, which cancels the effect of [`Pin`]. For `T: Unpin`,
+//! `Pin>` and `Box` function identically, as do `Pin<&mut T>` and
+//! `&mut T`.
 //!
 //! Note that pinning and `Unpin` only affect the pointed-to type `P::Target`, not the pointer
 //! type `P` itself that got wrapped in `Pin`. For example, whether or not `Box` is
@@ -65,11 +66,11 @@
 //! use std::marker::PhantomPinned;
 //! use std::ptr::NonNull;
 //!
-//! // This is a self-referential struct since the slice field points to the data field.
+//! // This is a self-referential struct because the slice field points to the data field.
 //! // We cannot inform the compiler about that with a normal reference,
-//! // since this pattern cannot be described with the usual borrowing rules.
-//! // Instead we use a raw pointer, though one which is known to not be null,
-//! // since we know it's pointing at the string.
+//! // as this pattern cannot be described with the usual borrowing rules.
+//! // Instead we use a raw pointer, though one which is known not to be null,
+//! // as we know it's pointing at the string.
 //! struct Unmovable {
 //!     data: String,
 //!     slice: NonNull,
@@ -146,7 +147,7 @@
 //! section needs to function correctly.
 //!
 //! Notice that this guarantee does *not* mean that memory does not leak! It is still
-//! completely okay not to ever call `drop` on a pinned element (e.g., you can still
+//! completely okay not ever to call `drop` on a pinned element (e.g., you can still
 //! call [`mem::forget`] on a `Pin>`). In the example of the doubly-linked
 //! list, that element would just stay in the list. However you may not free or reuse the storage
 //! *without calling `drop`*.
@@ -192,7 +193,7 @@
 //!     `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
 //!     the wrapper it is your responsibility *not* to add something like
 //!     `impl Unpin for Wrapper`. (Notice that adding a projection operation
-//!     requires unsafe code, so the fact that `Unpin` is a safe trait  does not break
+//!     requires unsafe code, so the fact that `Unpin` is a safe trait does not break
 //!     the principle that you only have to worry about any of this if you use `unsafe`.)
 //! 2.  The destructor of the wrapper must not move structural fields out of its argument. This
 //!     is the exact point that was raised in the [previous section][drop-impl]: `drop` takes
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index b4615aeb0db15..e324abd8e2f32 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -179,10 +179,15 @@ pub fn struct_error<'a, 'gcx, 'tcx>(
     struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
 }
 
+/// Packages the kind of error we got from the const code interpreter
+/// up with a Rust-level backtrace of where the error occured.
+/// Thsese should always be constructed by calling `.into()` on
+/// a `InterpError`. In `librustc_mir::interpret`, we have the `err!`
+/// macro for this
 #[derive(Debug, Clone)]
 pub struct EvalError<'tcx> {
     pub kind: InterpError<'tcx, u64>,
-    pub backtrace: Option>,
+    backtrace: Option>,
 }
 
 impl<'tcx> EvalError<'tcx> {
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index f892c1597057b..c421839513c01 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -503,32 +503,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                 move_from,
                 ..
             } => {
-                let try_remove_deref = match move_from {
-                    Place::Projection(box Projection {
-                        elem: ProjectionElem::Deref,
-                        ..
-                    }) => true,
-                    _ => false,
-                };
-                if try_remove_deref && snippet.starts_with('*') {
-                    // The snippet doesn't start with `*` in (e.g.) index
-                    // expressions `a[b]`, which roughly desugar to
-                    // `*Index::index(&a, b)` or
-                    // `*IndexMut::index_mut(&mut a, b)`.
-                    err.span_suggestion(
-                        span,
-                        "consider removing the `*`",
-                        snippet[1..].to_owned(),
-                        Applicability::Unspecified,
-                    );
-                } else {
-                    err.span_suggestion(
-                        span,
-                        "consider borrowing here",
-                        format!("&{}", snippet),
-                        Applicability::Unspecified,
-                    );
-                }
+                err.span_suggestion(
+                    span,
+                    "consider borrowing here",
+                    format!("&{}", snippet),
+                    Applicability::Unspecified,
+                );
 
                 if binds_to.is_empty() {
                     let place_ty = move_from.ty(self.mir, self.infcx.tcx).ty;
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index fac9665d968e2..a3297666113d4 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -663,6 +663,23 @@ where
         Ok(())
     }
 
+    /// Write an `Immediate` to memory.
+    #[inline(always)]
+    pub fn write_immediate_to_mplace(
+        &mut self,
+        src: Immediate,
+        dest: MPlaceTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx> {
+        self.write_immediate_to_mplace_no_validate(src, dest)?;
+
+        if M::enforce_validity(self) {
+            // Data got changed, better make sure it matches the type!
+            self.validate_operand(dest.into(), vec![], None, /*const_mode*/ false)?;
+        }
+
+        Ok(())
+    }
+
     /// Write an immediate to a place.
     /// If you use this you are responsible for validating that things got copied at the
     /// right type.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index dbaa4e557c66f..0d389b31f9075 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP};
 use rustc::ty::subst::InternalSubsts;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::ty::layout::{
-    LayoutOf, TyLayout, LayoutError,
-    HasTyCtxt, TargetDataLayout, HasDataLayout,
+    LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size,
 };
 
 use crate::interpret::{
@@ -333,6 +332,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                             this.ecx.operand_field(eval, field.index() as u64)
                         })?;
                     },
+                    ProjectionElem::Deref => {
+                        trace!("processing deref");
+                        eval = self.use_ecx(source_info, |this| {
+                            this.ecx.deref_operand(eval)
+                        })?.into();
+                    }
                     // We could get more projections by using e.g., `operand_projection`,
                     // but we do not even have the stack frame set up properly so
                     // an `Index` projection would throw us off-track.
@@ -363,8 +368,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
             Rvalue::Use(ref op) => {
                 self.eval_operand(op, source_info)
             },
+            Rvalue::Ref(_, _, ref place) => {
+                let src = self.eval_place(place, source_info)?;
+                let mplace = src.try_as_mplace().ok()?;
+                Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into())
+            },
             Rvalue::Repeat(..) |
-            Rvalue::Ref(..) |
             Rvalue::Aggregate(..) |
             Rvalue::NullaryOp(NullOp::Box, _) |
             Rvalue::Discriminant(..) => None,
@@ -376,10 +385,30 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                     this.ecx.cast(op, kind, dest.into())?;
                     Ok(dest.into())
                 })
-            }
+            },
+            Rvalue::Len(ref place) => {
+                let place = self.eval_place(&place, source_info)?;
+                let mplace = place.try_as_mplace().ok()?;
+
+                if let ty::Slice(_) = mplace.layout.ty.sty {
+                    let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap();
 
-            // FIXME(oli-obk): evaluate static/constant slice lengths
-            Rvalue::Len(_) => None,
+                    Some(ImmTy {
+                        imm: Immediate::Scalar(
+                            Scalar::from_uint(
+                                len,
+                                Size::from_bits(
+                                    self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64
+                                )
+                            ).into(),
+                        ),
+                        layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
+                    }.into())
+                } else {
+                    trace!("not slice: {:?}", mplace.layout.ty.sty);
+                    None
+                }
+            },
             Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
                 type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(
                     ImmTy {
@@ -525,12 +554,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
         source_info: SourceInfo,
     ) {
         trace!("attepting to replace {:?} with {:?}", rval, value);
-        self.ecx.validate_operand(
-            value,
-            vec![],
-            None,
-            true,
-        ).expect("value should already be a valid const");
+        if let Err(e) = self.ecx.validate_operand(value, vec![], None, true) {
+            trace!("validation error, attempt failed: {:?}", e);
+            return;
+        }
 
         // FIXME> figure out what tho do when try_read_immediate fails
         let imm = self.use_ecx(source_info, |this| {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 03d16feb483a9..a717ef20a8444 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2768,7 +2768,10 @@ impl Clean for hir::Ty {
                 };
                 let length = match cx.tcx.const_eval(param_env.and(cid)) {
                     Ok(length) => print_const(cx, length),
-                    Err(_) => "_".to_string(),
+                    Err(_) => cx.sess()
+                                .source_map()
+                                .span_to_snippet(cx.tcx.def_span(def_id))
+                                .unwrap_or_else(|_| "_".to_string()),
                 };
                 Array(box ty.clean(cx), length)
             },
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index 9abad83fdb039..30e23f1007f20 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -87,3 +87,5 @@ std_detect_dlsym_getauxval = []
 [package.metadata.fortanix-sgx]
 # Maximum possible number of threads when testing
 threads = 125
+# Maximum heap size
+heap_size = 0x8000000
diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs
new file mode 100644
index 0000000000000..2d04822c0e789
--- /dev/null
+++ b/src/test/mir-opt/const_prop/ref_deref.rs
@@ -0,0 +1,21 @@
+fn main() {
+    *(&4);
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+//     ...
+//     _2 = &(promoted[0]: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+//     ...
+//     _2 = const Scalar(AllocId(0).0x0) : &i32;
+//     _1 = const 4i32;
+//     ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.rs b/src/test/mir-opt/const_prop/reify_fn_ptr.rs
new file mode 100644
index 0000000000000..809eb19ade899
--- /dev/null
+++ b/src/test/mir-opt/const_prop/reify_fn_ptr.rs
@@ -0,0 +1,25 @@
+fn main() {
+    let _ = main as usize as *const fn();
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = const main as fn() (Pointer(ReifyFnPointer));
+//      _2 = move _3 as usize (Misc);
+//      ...
+//      _1 = move _2 as *const fn() (Misc);
+//      ...
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = const Scalar(AllocId(1).0x0) : fn();
+//      _2 = move _3 as usize (Misc);
+//      ...
+//      _1 = const Scalar(AllocId(1).0x0) : *const fn();
+//      ...
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs
index 3435ca07f4cd8..5babeb195a826 100644
--- a/src/test/mir-opt/const_prop/slice_len.rs
+++ b/src/test/mir-opt/const_prop/slice_len.rs
@@ -1,22 +1,22 @@
-fn test() -> &'static [u32] {
-    &[1, 2]
-}
-
 fn main() {
-    let x = test()[0];
+    (&[1u32, 2, 3] as &[u32])[1];
 }
 
 // END RUST SOURCE
 // START rustc.main.ConstProp.before.mir
-//  bb1: {
+//  bb0: {
 //      ...
-//      _3 = const 0usize;
-//      _4 = Len((*_2));
-//      _5 = Lt(_3, _4);
-//      assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+//      _4 = &(promoted[0]: [u32; 3]);
+//      _3 = _4;
+//      _2 = move _3 as &[u32] (Pointer(Unsize));
+//      ...
+//      _6 = const 1usize;
+//      _7 = Len((*_2));
+//      _8 = Lt(_6, _7);
+//      assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
 //  }
-//  bb2: {
-//      _1 = (*_2)[_3];
+//  bb1: {
+//      _1 = (*_2)[_6];
 //      ...
 //      return;
 //  }
@@ -24,13 +24,17 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 //  bb0: {
 //      ...
-//      _3 = const 0usize;
-//      _4 = Len((*_2));
-//      _5 = Lt(_3, _4);
-//      assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+//      _4 = const Scalar(AllocId(0).0x0) : &[u32; 3];
+//      _3 = const Scalar(AllocId(0).0x0) : &[u32; 3];
+//      _2 = move _3 as &[u32] (Pointer(Unsize));
+//      ...
+//      _6 = const 1usize;
+//      _7 = const 3usize;
+//      _8 = const true;
+//      assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
 //  }
-//  bb2: {
-//      _1 = (*_2)[_3];
+//  bb1: {
+//      _1 = (*_2)[_6];
 //      ...
 //      return;
 //  }
diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs
new file mode 100644
index 0000000000000..60d96770f7eae
--- /dev/null
+++ b/src/test/rustdoc/const-generics/const-generic-slice.rs
@@ -0,0 +1,12 @@
+#![crate_name = "foo"]
+#![feature(const_generics)]
+
+pub trait Array {
+    type Item;
+}
+
+// @has foo/trait.Array.html
+// @has - '//h3[@class="impl"]' 'impl Array for [T; N]'
+impl  Array for [T; N] {
+    type Item = T;
+}
diff --git a/src/test/ui/access-mode-in-closures.stderr b/src/test/ui/access-mode-in-closures.stderr
index 424d7ebb37444..349e3f4a836a0 100644
--- a/src/test/ui/access-mode-in-closures.stderr
+++ b/src/test/ui/access-mode-in-closures.stderr
@@ -6,7 +6,7 @@ LL |         match *s { S(v) => v }
    |               |      |
    |               |      data moved here
    |               |      move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait
-   |               help: consider removing the `*`: `s`
+   |               help: consider borrowing here: `&*s`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr
index 908b2c0ff5ee8..5880a1abb818c 100644
--- a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr
+++ b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr
@@ -5,7 +5,7 @@ LL |         let _b = *y;
    |                  ^^
    |                  |
    |                  move occurs because `*y` has type `std::boxed::Box`, which does not implement the `Copy` trait
-   |                  help: consider removing the `*`: `y`
+   |                  help: consider borrowing here: `&*y`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr
index 13d3faab6508a..d56b9f562c932 100644
--- a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr
+++ b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr
@@ -2,7 +2,7 @@ error[E0507]: cannot move out of `f.0` which is behind a shared reference
   --> $DIR/borrowck-move-error-with-note.rs:11:11
    |
 LL |     match *f {
-   |           ^^ help: consider removing the `*`: `f`
+   |           ^^ help: consider borrowing here: `&*f`
 LL |         Foo::Foo1(num1,
    |                   ---- data moved here
 LL |                   num2) => (),
diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
index 6c806e0896b37..7dfae33920e1c 100644
--- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
+++ b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
@@ -5,7 +5,7 @@ LL |     let y = *x;
    |             ^^
    |             |
    |             move occurs because `*x` has type `std::boxed::Box`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `x`
+   |             help: consider borrowing here: `&*x`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
index da3e5c54b75f7..1501644fac758 100644
--- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
@@ -5,7 +5,7 @@ LL |     let _x = *Rc::new("hi".to_string());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
-   |              help: consider removing the `*`: `Rc::new("hi".to_string())`
+   |              help: consider borrowing here: `&*Rc::new("hi".to_string())`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
index 6ba801b9714bf..78d44f3206199 100644
--- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
+++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
@@ -5,7 +5,7 @@ LL |             *array
    |             ^^^^^^
    |             |
    |             move occurs because `*array` has type `std::vec::Vec`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `array`
+   |             help: consider borrowing here: `&*array`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index c9d5ede61ade4..c9f3a7659f9cd 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -16,6 +16,12 @@ warning: attempt to divide by zero
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^
 
+warning: this expression will panic at runtime
+  --> $DIR/promoted_errors.rs:9:20
+   |
+LL |     println!("{}", 1/(1-1));
+   |                    ^^^^^^^ attempt to divide by zero
+
 warning: attempt to divide by zero
   --> $DIR/promoted_errors.rs:11:14
    |
@@ -34,6 +40,12 @@ warning: attempt to divide by zero
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^
 
+warning: this expression will panic at runtime
+  --> $DIR/promoted_errors.rs:14:20
+   |
+LL |     println!("{}", 1/(false as u32));
+   |                    ^^^^^^^^^^^^^^^^ attempt to divide by zero
+
 warning: attempt to divide by zero
   --> $DIR/promoted_errors.rs:16:14
    |
diff --git a/src/test/ui/issues/issue-20801.stderr b/src/test/ui/issues/issue-20801.stderr
index 1bbd874a44802..d276231dc0c96 100644
--- a/src/test/ui/issues/issue-20801.stderr
+++ b/src/test/ui/issues/issue-20801.stderr
@@ -5,7 +5,7 @@ LL |     let a = unsafe { *mut_ref() };
    |                      ^^^^^^^^^^
    |                      |
    |                      move occurs because value has type `T`, which does not implement the `Copy` trait
-   |                      help: consider removing the `*`: `mut_ref()`
+   |                      help: consider borrowing here: `&*mut_ref()`
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/issue-20801.rs:29:22
@@ -14,7 +14,7 @@ LL |     let b = unsafe { *imm_ref() };
    |                      ^^^^^^^^^^
    |                      |
    |                      move occurs because value has type `T`, which does not implement the `Copy` trait
-   |                      help: consider removing the `*`: `imm_ref()`
+   |                      help: consider borrowing here: `&*imm_ref()`
 
 error[E0507]: cannot move out of a raw pointer
   --> $DIR/issue-20801.rs:32:22
@@ -23,7 +23,7 @@ LL |     let c = unsafe { *mut_ptr() };
    |                      ^^^^^^^^^^
    |                      |
    |                      move occurs because value has type `T`, which does not implement the `Copy` trait
-   |                      help: consider removing the `*`: `mut_ptr()`
+   |                      help: consider borrowing here: `&*mut_ptr()`
 
 error[E0507]: cannot move out of a raw pointer
   --> $DIR/issue-20801.rs:35:22
@@ -32,7 +32,7 @@ LL |     let d = unsafe { *const_ptr() };
    |                      ^^^^^^^^^^^^
    |                      |
    |                      move occurs because value has type `T`, which does not implement the `Copy` trait
-   |                      help: consider removing the `*`: `const_ptr()`
+   |                      help: consider borrowing here: `&*const_ptr()`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/nll/cannot-move-block-spans.stderr b/src/test/ui/nll/cannot-move-block-spans.stderr
index 4a9635b060db3..7db5d731acd17 100644
--- a/src/test/ui/nll/cannot-move-block-spans.stderr
+++ b/src/test/ui/nll/cannot-move-block-spans.stderr
@@ -5,7 +5,7 @@ LL |     let x = { *r };
    |               ^^
    |               |
    |               move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait
-   |               help: consider removing the `*`: `r`
+   |               help: consider borrowing here: `&*r`
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:6:22
@@ -14,7 +14,7 @@ LL |     let y = unsafe { *r };
    |                      ^^
    |                      |
    |                      move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait
-   |                      help: consider removing the `*`: `r`
+   |                      help: consider borrowing here: `&*r`
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:7:26
@@ -23,7 +23,7 @@ LL |     let z = loop { break *r; };
    |                          ^^
    |                          |
    |                          move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait
-   |                          help: consider removing the `*`: `r`
+   |                          help: consider borrowing here: `&*r`
 
 error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array
   --> $DIR/cannot-move-block-spans.rs:11:15
@@ -62,7 +62,7 @@ LL |     let x = { let mut u = 0; u += 1; *r };
    |                                      ^^
    |                                      |
    |                                      move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait
-   |                                      help: consider removing the `*`: `r`
+   |                                      help: consider borrowing here: `&*r`
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:18:45
@@ -71,7 +71,7 @@ LL |     let y = unsafe { let mut u = 0; u += 1; *r };
    |                                             ^^
    |                                             |
    |                                             move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait
-   |                                             help: consider removing the `*`: `r`
+   |                                             help: consider borrowing here: `&*r`
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:19:49
@@ -80,7 +80,7 @@ LL |     let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
    |                                                 ^^
    |                                                 |
    |                                                 move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait
-   |                                                 help: consider removing the `*`: `r`
+   |                                                 help: consider borrowing here: `&*r`
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr
index 086f7bcdc4f27..7139617a97a4f 100644
--- a/src/test/ui/nll/move-errors.stderr
+++ b/src/test/ui/nll/move-errors.stderr
@@ -5,7 +5,7 @@ LL |     let b = *a;
    |             ^^
    |             |
    |             move occurs because `*a` has type `A`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `a`
+   |             help: consider borrowing here: `&*a`
 
 error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
   --> $DIR/move-errors.rs:12:13
@@ -24,7 +24,7 @@ LL |     let s = **r;
    |             ^^^
    |             |
    |             move occurs because `**r` has type `A`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `*r`
+   |             help: consider borrowing here: `&**r`
 
 error[E0507]: cannot move out of an `Rc`
   --> $DIR/move-errors.rs:27:13
@@ -33,7 +33,7 @@ LL |     let s = *r;
    |             ^^
    |             |
    |             move occurs because value has type `A`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `r`
+   |             help: consider borrowing here: `&*r`
 
 error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
   --> $DIR/move-errors.rs:32:13
@@ -49,7 +49,7 @@ error[E0507]: cannot move out of `a.0` which is behind a shared reference
   --> $DIR/move-errors.rs:38:16
    |
 LL |     let A(s) = *a;
-   |           -    ^^ help: consider removing the `*`: `a`
+   |           -    ^^ help: consider borrowing here: `&*a`
    |           |
    |           data moved here
    |           move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
@@ -148,7 +148,7 @@ error[E0507]: cannot move out of `x.0` which is behind a shared reference
   --> $DIR/move-errors.rs:110:11
    |
 LL |     match *x {
-   |           ^^ help: consider removing the `*`: `x`
+   |           ^^ help: consider borrowing here: `&*x`
 LL |
 LL |         Ok(s) | Err(s) => (),
    |            -
diff --git a/src/test/ui/std-uncopyable-atomics.stderr b/src/test/ui/std-uncopyable-atomics.stderr
index 189a27db382cd..9db9fcf40f82c 100644
--- a/src/test/ui/std-uncopyable-atomics.stderr
+++ b/src/test/ui/std-uncopyable-atomics.stderr
@@ -5,7 +5,7 @@ LL |     let x = *&x;
    |             ^^^
    |             |
    |             move occurs because value has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `&x`
+   |             help: consider borrowing here: `&*&x`
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/std-uncopyable-atomics.rs:11:13
@@ -14,7 +14,7 @@ LL |     let x = *&x;
    |             ^^^
    |             |
    |             move occurs because value has type `std::sync::atomic::AtomicIsize`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `&x`
+   |             help: consider borrowing here: `&*&x`
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/std-uncopyable-atomics.rs:13:13
@@ -23,7 +23,7 @@ LL |     let x = *&x;
    |             ^^^
    |             |
    |             move occurs because value has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `&x`
+   |             help: consider borrowing here: `&*&x`
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/std-uncopyable-atomics.rs:15:13
@@ -32,7 +32,7 @@ LL |     let x = *&x;
    |             ^^^
    |             |
    |             move occurs because value has type `std::sync::atomic::AtomicPtr`, which does not implement the `Copy` trait
-   |             help: consider removing the `*`: `&x`
+   |             help: consider borrowing here: `&*&x`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.rs b/src/test/ui/suggestions/dont-suggest-ref/simple.rs
index 31ab1a6639acc..69b303a66237e 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/simple.rs
+++ b/src/test/ui/suggestions/dont-suggest-ref/simple.rs
@@ -37,26 +37,26 @@ pub fn main() {
 
     let X(_t) = *s;
     //~^ ERROR cannot move
-    //~| HELP consider removing the `*`
+    //~| HELP consider borrowing here
     //~| SUGGESTION s
     if let Either::One(_t) = *r { }
     //~^ ERROR cannot move
-    //~| HELP consider removing the `*`
+    //~| HELP consider borrowing here
     //~| SUGGESTION r
     while let Either::One(_t) = *r { }
     //~^ ERROR cannot move
-    //~| HELP consider removing the `*`
+    //~| HELP consider borrowing here
     //~| SUGGESTION r
     match *r {
         //~^ ERROR cannot move
-        //~| HELP consider removing the `*`
+        //~| HELP consider borrowing here
         //~| SUGGESTION r
         Either::One(_t)
         | Either::Two(_t) => (),
     }
     match *r {
         //~^ ERROR cannot move
-        //~| HELP consider removing the `*`
+        //~| HELP consider borrowing here
         //~| SUGGESTION r
         Either::One(_t) => (),
         Either::Two(ref _t) => (),
@@ -65,26 +65,26 @@ pub fn main() {
 
     let X(_t) = *sm;
     //~^ ERROR cannot move
-    //~| HELP consider removing the `*`
+    //~| HELP consider borrowing here
     //~| SUGGESTION sm
     if let Either::One(_t) = *rm { }
     //~^ ERROR cannot move
-    //~| HELP consider removing the `*`
+    //~| HELP consider borrowing here
     //~| SUGGESTION rm
     while let Either::One(_t) = *rm { }
     //~^ ERROR cannot move
-    //~| HELP consider removing the `*`
+    //~| HELP consider borrowing here
     //~| SUGGESTION rm
     match *rm {
         //~^ ERROR cannot move
-        //~| HELP consider removing the `*`
+        //~| HELP consider borrowing here
         //~| SUGGESTION rm
         Either::One(_t)
         | Either::Two(_t) => (),
     }
     match *rm {
         //~^ ERROR cannot move
-        //~| HELP consider removing the `*`
+        //~| HELP consider borrowing here
         //~| SUGGESTION rm
         Either::One(_t) => (),
         Either::Two(ref _t) => (),
@@ -92,7 +92,7 @@ pub fn main() {
     }
     match *rm {
         //~^ ERROR cannot move
-        //~| HELP consider removing the `*`
+        //~| HELP consider borrowing here
         //~| SUGGESTION rm
         Either::One(_t) => (),
         Either::Two(ref mut _t) => (),
diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
index bde3afa3840a2..cb3ce5991aeee 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
+++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
@@ -2,7 +2,7 @@ error[E0507]: cannot move out of `s.0` which is behind a shared reference
   --> $DIR/simple.rs:38:17
    |
 LL |     let X(_t) = *s;
-   |           --    ^^ help: consider removing the `*`: `s`
+   |           --    ^^ help: consider borrowing here: `&*s`
    |           |
    |           data moved here
    |           move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
@@ -11,7 +11,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference
   --> $DIR/simple.rs:42:30
    |
 LL |     if let Either::One(_t) = *r { }
-   |                        --    ^^ help: consider removing the `*`: `r`
+   |                        --    ^^ help: consider borrowing here: `&*r`
    |                        |
    |                        data moved here
    |                        move occurs because `_t` has type `X`, which does not implement the `Copy` trait
@@ -20,7 +20,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference
   --> $DIR/simple.rs:46:33
    |
 LL |     while let Either::One(_t) = *r { }
-   |                           --    ^^ help: consider removing the `*`: `r`
+   |                           --    ^^ help: consider borrowing here: `&*r`
    |                           |
    |                           data moved here
    |                           move occurs because `_t` has type `X`, which does not implement the `Copy` trait
@@ -29,7 +29,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference
   --> $DIR/simple.rs:50:11
    |
 LL |     match *r {
-   |           ^^ help: consider removing the `*`: `r`
+   |           ^^ help: consider borrowing here: `&*r`
 ...
 LL |         Either::One(_t)
    |                     --
@@ -41,7 +41,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference
   --> $DIR/simple.rs:57:11
    |
 LL |     match *r {
-   |           ^^ help: consider removing the `*`: `r`
+   |           ^^ help: consider borrowing here: `&*r`
 ...
 LL |         Either::One(_t) => (),
    |                     --
@@ -53,7 +53,7 @@ error[E0507]: cannot move out of `sm.0` which is behind a mutable reference
   --> $DIR/simple.rs:66:17
    |
 LL |     let X(_t) = *sm;
-   |           --    ^^^ help: consider removing the `*`: `sm`
+   |           --    ^^^ help: consider borrowing here: `&*sm`
    |           |
    |           data moved here
    |           move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
@@ -62,7 +62,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
   --> $DIR/simple.rs:70:30
    |
 LL |     if let Either::One(_t) = *rm { }
-   |                        --    ^^^ help: consider removing the `*`: `rm`
+   |                        --    ^^^ help: consider borrowing here: `&*rm`
    |                        |
    |                        data moved here
    |                        move occurs because `_t` has type `X`, which does not implement the `Copy` trait
@@ -71,7 +71,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
   --> $DIR/simple.rs:74:33
    |
 LL |     while let Either::One(_t) = *rm { }
-   |                           --    ^^^ help: consider removing the `*`: `rm`
+   |                           --    ^^^ help: consider borrowing here: `&*rm`
    |                           |
    |                           data moved here
    |                           move occurs because `_t` has type `X`, which does not implement the `Copy` trait
@@ -80,7 +80,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
   --> $DIR/simple.rs:78:11
    |
 LL |     match *rm {
-   |           ^^^ help: consider removing the `*`: `rm`
+   |           ^^^ help: consider borrowing here: `&*rm`
 ...
 LL |         Either::One(_t)
    |                     --
@@ -92,7 +92,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
   --> $DIR/simple.rs:85:11
    |
 LL |     match *rm {
-   |           ^^^ help: consider removing the `*`: `rm`
+   |           ^^^ help: consider borrowing here: `&*rm`
 ...
 LL |         Either::One(_t) => (),
    |                     --
@@ -104,7 +104,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
   --> $DIR/simple.rs:93:11
    |
 LL |     match *rm {
-   |           ^^^ help: consider removing the `*`: `rm`
+   |           ^^^ help: consider borrowing here: `&*rm`
 ...
 LL |         Either::One(_t) => (),
    |                     --