about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/cell.rs25
-rw-r--r--src/librustc_error_codes/error_codes.rs2
-rw-r--r--src/librustc_error_codes/error_codes/E0539.md48
-rw-r--r--src/librustc_mir/interpret/validity.rs92
-rw-r--r--src/librustc_mir/transform/const_prop.rs10
-rw-r--r--src/librustc_typeck/check/coercion.rs18
-rw-r--r--src/librustc_typeck/check/demand.rs136
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/libstd/sync/once.rs2
-rw-r--r--src/test/run-make/wasm-panic-small/foo.rs2
-rw-r--r--src/test/ui/issues/issue-32122-1.stderr2
-rw-r--r--src/test/ui/issues/issue-32122-2.stderr2
-rw-r--r--src/test/ui/issues/issue-71676-1.fixed53
-rw-r--r--src/test/ui/issues/issue-71676-1.rs53
-rw-r--r--src/test/ui/issues/issue-71676-1.stderr55
-rw-r--r--src/test/ui/issues/issue-71676-2.rs42
-rw-r--r--src/test/ui/issues/issue-71676-2.stderr16
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr108
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr108
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr108
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.rs53
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.stderr3
-rw-r--r--src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs2
-rw-r--r--src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs2
24 files changed, 677 insertions, 269 deletions
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index a922d4f118b..0f2665eba6f 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -1023,6 +1023,31 @@ impl<T: ?Sized> RefCell<T> {
     }
 }
 
+impl<T: Default> RefCell<T> {
+    /// Takes the wrapped value, leaving `Default::default()` in its place.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the value is currently borrowed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(refcell_take)]
+    /// use std::cell::RefCell;
+    ///
+    /// let c = RefCell::new(5);
+    /// let five = c.take();
+    ///
+    /// assert_eq!(five, 5);
+    /// assert_eq!(c.into_inner(), 0);
+    /// ```
+    #[unstable(feature = "refcell_take", issue = "71395")]
+    pub fn take(&self) -> T {
+        self.replace(Default::default())
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}
 
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index bf4a6c52ab8..e01412bc21c 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -281,6 +281,7 @@ E0535: include_str!("./error_codes/E0535.md"),
 E0536: include_str!("./error_codes/E0536.md"),
 E0537: include_str!("./error_codes/E0537.md"),
 E0538: include_str!("./error_codes/E0538.md"),
+E0539: include_str!("./error_codes/E0539.md"),
 E0541: include_str!("./error_codes/E0541.md"),
 E0550: include_str!("./error_codes/E0550.md"),
 E0551: include_str!("./error_codes/E0551.md"),
@@ -570,7 +571,6 @@ E0753: include_str!("./error_codes/E0753.md"),
     E0521, // borrowed data escapes outside of closure
     E0523,
 //  E0526, // shuffle indices are not constant
-    E0539, // incorrect meta item
     E0540, // multiple rustc_deprecated attributes
     E0542, // missing 'since'
     E0543, // missing 'reason'
diff --git a/src/librustc_error_codes/error_codes/E0539.md b/src/librustc_error_codes/error_codes/E0539.md
new file mode 100644
index 00000000000..df2d7d910bb
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0539.md
@@ -0,0 +1,48 @@
+An invalid meta-item was used inside an attribute.
+
+Erroneous code example:
+
+```compile_fail,E0539
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[rustc_deprecated(reason)] // error!
+#[unstable(feature = "deprecated_fn", issue = "123")]
+fn deprecated() {}
+
+#[unstable(feature = "unstable_struct", issue)] // error!
+struct Unstable;
+
+#[rustc_const_unstable(feature)] // error!
+const fn unstable_fn() {}
+
+#[stable(feature = "stable_struct", since)] // error!
+struct Stable;
+
+#[rustc_const_stable(feature)] // error!
+const fn stable_fn() {}
+```
+
+Meta items are the key-value pairs inside of an attribute.
+To fix these issues you need to give required key-value pairs.
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[rustc_deprecated(since = "1.39.0", reason = "reason")] // ok!
+#[unstable(feature = "deprecated_fn", issue = "123")]
+fn deprecated() {}
+
+#[unstable(feature = "unstable_struct", issue = "123")] // ok!
+struct Unstable;
+
+#[rustc_const_unstable(feature = "unstable_fn", issue = "124")] // ok!
+const fn unstable_fn() {}
+
+#[stable(feature = "stable_struct", since = "1.39.0")] // ok!
+struct Stable;
+
+#[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
+const fn stable_fn() {}
+```
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index a9586b74a56..b6991349ff4 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -11,6 +11,7 @@ use std::ops::RangeInclusive;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::symbol::{sym, Symbol};
@@ -24,43 +25,71 @@ use super::{
 };
 
 macro_rules! throw_validation_failure {
-    ($what:expr, $where:expr, $details:expr) => {{
-        let mut msg = format!("encountered {}", $what);
-        let where_ = &$where;
-        if !where_.is_empty() {
-            msg.push_str(" at ");
-            write_path(&mut msg, where_);
-        }
-        write!(&mut msg, ", but expected {}", $details).unwrap();
-        throw_ub!(ValidationFailure(msg))
-    }};
-    ($what:expr, $where:expr) => {{
+    ($what:expr, $where:expr $(, $expected:expr )?) => {{
         let mut msg = format!("encountered {}", $what);
         let where_ = &$where;
         if !where_.is_empty() {
             msg.push_str(" at ");
             write_path(&mut msg, where_);
         }
+        $( write!(&mut msg, ", but expected {}", $expected).unwrap(); )?
         throw_ub!(ValidationFailure(msg))
     }};
 }
 
+/// Returns a validation failure for any Err value of $e.
+// FIXME: Replace all usages of try_validation! with try_validation_pat!.
 macro_rules! try_validation {
-    ($e:expr, $what:expr, $where:expr, $details:expr) => {{
-        match $e {
-            Ok(x) => x,
-            // We re-throw the error, so we are okay with allocation:
-            // this can only slow down builds that fail anyway.
-            Err(_) => throw_validation_failure!($what, $where, $details),
-        }
+    ($e:expr, $what:expr, $where:expr $(, $expected:expr )?) => {{
+        try_validation_pat!($e, $where, {
+            _ => { "{}", $what } $( expected { "{}", $expected } )?,
+        })
     }};
-
-    ($e:expr, $what:expr, $where:expr) => {{
+}
+/// Like try_validation, but will throw a validation error if any of the patterns in $p are
+/// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns
+/// as a kind of validation blacklist:
+///
+/// ```
+/// let v = try_validation_pat!(some_fn(), some_path, {
+///     Foo | Bar | Baz => { "some failure" },
+/// });
+/// // Failures that match $p are thrown up as validation errors, but other errors are passed back
+/// // unchanged.
+/// ```
+///
+/// An additional expected parameter can also be added to the failure message:
+///
+/// ```
+/// let v = try_validation_pat!(some_fn(), some_path, {
+///     Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" },
+/// });
+/// ```
+///
+/// An additional nicety is that both parameters actually take format args, so you can just write
+/// the format string in directly:
+///
+/// ```
+/// let v = try_validation_pat!(some_fn(), some_path, {
+///     Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value },
+/// });
+/// ```
+///
+macro_rules! try_validation_pat {
+    ($e:expr, $where:expr, { $( $p:pat )|+ =>
+        { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? $( , )?}) => {{
         match $e {
             Ok(x) => x,
-            // We re-throw the error, so we are okay with allocation:
-            // this can only slow down builds that fail anyway.
-            Err(_) => throw_validation_failure!($what, $where),
+            // We catch the error and turn it into a validation failure. We are okay with
+            // allocation here as this can only slow down builds that fail anyway.
+            $( Err(InterpErrorInfo { kind: $p, .. }) )|+ =>
+                throw_validation_failure!(
+                    format_args!($( $what_fmt ),+),
+                    $where
+                    $(, format_args!($( $expected_fmt ),+))?
+                ),
+            #[allow(unreachable_patterns)]
+            Err(e) => Err::<!, _>(e)?,
         }
     }};
 }
@@ -492,11 +521,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 // We are conservative with undef for integers, but try to
                 // actually enforce the strict rules for raw pointers (mostly because
                 // that lets us re-use `ref_to_mplace`).
-                let place = try_validation!(
-                    self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
-                    "uninitialized raw pointer",
-                    self.path
-                );
+                let place = try_validation_pat!(self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), self.path, {
+                    err_ub!(InvalidUndefBytes(..)) => { "uninitialized raw pointer" },
+                });
                 if place.layout.is_unsized() {
                     self.check_wide_ptr_meta(place.meta, place.layout)?;
                 }
@@ -800,7 +827,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
 
                                 throw_validation_failure!("uninitialized bytes", self.path)
                             }
-                            // Other errors shouldn't be possible
+                            // Propagate upwards (that will also check for unexpected errors).
                             _ => return Err(err),
                         }
                     }
@@ -843,9 +870,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Run it.
         match visitor.visit_value(op) {
             Ok(()) => Ok(()),
-            // We should only get validation errors here. Avoid other errors as
-            // those do not show *where* in the value the issue lies.
+            // Pass through validation failures.
             Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err),
+            // Also pass through InvalidProgram, those just indicate that we could not
+            // validate and each caller will know best what to do with them.
+            Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err),
+            // Avoid other errors as those do not show *where* in the value the issue lies.
             Err(err) => bug!("Unexpected error during validation: {}", err),
         }
     }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 2673bab2028..aae80185b4d 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -549,11 +549,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             return None;
         }
 
-        // FIXME we need to revisit this for #67176
-        if rvalue.needs_subst() {
-            return None;
-        }
-
         // Perform any special handling for specific Rvalue types.
         // Generally, checks here fall into one of two categories:
         //   1. Additional checking to provide useful lints to the user
@@ -594,6 +589,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             _ => {}
         }
 
+        // FIXME we need to revisit this for #67176
+        if rvalue.needs_subst() {
+            return None;
+        }
+
         self.use_ecx(|this| {
             trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
             this.ecx.eval_rvalue_into_place(rvalue, place)?;
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index bf36b2cdffe..86cafa0b8ca 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -74,7 +74,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 use smallvec::{smallvec, SmallVec};
 use std::ops::Deref;
 
-pub struct Coerce<'a, 'tcx> {
+struct Coerce<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     cause: ObligationCause<'tcx>,
     use_lub: bool,
@@ -126,7 +126,7 @@ fn success<'tcx>(
 }
 
 impl<'f, 'tcx> Coerce<'f, 'tcx> {
-    pub fn new(
+    fn new(
         fcx: &'f FnCtxt<'f, 'tcx>,
         cause: ObligationCause<'tcx>,
         allow_two_phase: AllowTwoPhase,
@@ -134,7 +134,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         Coerce { fcx, cause, allow_two_phase, use_lub: false }
     }
 
-    pub fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
+    fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
         debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
         self.commit_if_ok(|_| {
             if self.use_lub {
@@ -841,6 +841,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.probe(|_| coerce.coerce(source, target)).is_ok()
     }
 
+    /// Given a type and a target type, this function will calculate and return
+    /// how many dereference steps needed to achieve `expr_ty <: target`. If
+    /// it's not possible, return `None`.
+    pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize> {
+        let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable);
+        // We don't ever need two-phase here since we throw out the result of the coercion
+        let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
+        coerce
+            .autoderef(rustc_span::DUMMY_SP, expr_ty)
+            .find_map(|(ty, steps)| coerce.unify(ty, target).ok().map(|_| steps))
+    }
+
     /// Given some expressions, their known unified type and another expression,
     /// tries to unify the types, potentially inserting coercions on any of the
     /// provided expressions and returns their LUB (aka "common supertype").
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 65ef9cad874..9e14efb67a9 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -1,4 +1,3 @@
-use crate::check::coercion::Coerce;
 use crate::check::FnCtxt;
 use rustc_infer::infer::InferOk;
 use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -9,7 +8,6 @@ use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, Node};
-use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::sym;
@@ -355,6 +353,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    fn replace_prefix<A, B, C>(&self, s: A, old: B, new: C) -> Option<String>
+    where
+        A: AsRef<str>,
+        B: AsRef<str>,
+        C: AsRef<str>,
+    {
+        let s = s.as_ref();
+        let old = old.as_ref();
+        if s.starts_with(old) { Some(new.as_ref().to_owned() + &s[old.len()..]) } else { None }
+    }
+
     /// This function is used to determine potential "simple" improvements or users' errors and
     /// provide them useful help. For example:
     ///
@@ -376,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
-    ) -> Option<(Span, &'static str, String)> {
+    ) -> Option<(Span, &'static str, String, Applicability)> {
         let sm = self.sess().source_map();
         let sp = expr.span;
         if sm.is_imported(sp) {
@@ -400,11 +409,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
                     if let hir::ExprKind::Lit(_) = expr.kind {
                         if let Ok(src) = sm.span_to_snippet(sp) {
-                            if src.starts_with("b\"") {
+                            if let Some(src) = self.replace_prefix(src, "b\"", "\"") {
                                 return Some((
                                     sp,
                                     "consider removing the leading `b`",
-                                    src[1..].to_string(),
+                                    src,
+                                    Applicability::MachineApplicable,
                                 ));
                             }
                         }
@@ -413,11 +423,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
                     if let hir::ExprKind::Lit(_) = expr.kind {
                         if let Ok(src) = sm.span_to_snippet(sp) {
-                            if src.starts_with('"') {
+                            if let Some(src) = self.replace_prefix(src, "\"", "b\"") {
                                 return Some((
                                     sp,
                                     "consider adding a leading `b`",
-                                    format!("b{}", src),
+                                    src,
+                                    Applicability::MachineApplicable,
                                 ));
                             }
                         }
@@ -470,7 +481,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let sugg_expr = if needs_parens { format!("({})", src) } else { src };
 
                         if let Some(sugg) = self.can_use_as_ref(expr) {
-                            return Some(sugg);
+                            return Some((
+                                sugg.0,
+                                sugg.1,
+                                sugg.2,
+                                Applicability::MachineApplicable,
+                            ));
                         }
                         let field_name = if is_struct_pat_shorthand_field {
                             format!("{}: ", sugg_expr)
@@ -495,6 +511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         "consider dereferencing here to assign to the mutable \
                                          borrowed piece of memory",
                                         format!("*{}", src),
+                                        Applicability::MachineApplicable,
                                     ));
                                 }
                             }
@@ -505,11 +522,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 sp,
                                 "consider mutably borrowing here",
                                 format!("{}&mut {}", field_name, sugg_expr),
+                                Applicability::MachineApplicable,
                             ),
                             hir::Mutability::Not => (
                                 sp,
                                 "consider borrowing here",
                                 format!("{}&{}", field_name, sugg_expr),
+                                Applicability::MachineApplicable,
                             ),
                         });
                     }
@@ -526,51 +545,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // We have `&T`, check if what was expected was `T`. If so,
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
-                    if let Ok(code) = sm.span_to_snippet(sp) {
-                        if code.starts_with('&') {
+                    if let Ok(src) = sm.span_to_snippet(sp) {
+                        if let Some(src) = self.replace_prefix(src, "&", "") {
                             return Some((
                                 sp,
                                 "consider removing the borrow",
-                                code[1..].to_string(),
+                                src,
+                                Applicability::MachineApplicable,
                             ));
                         }
                     }
                     return None;
                 }
                 if let Ok(code) = sm.span_to_snippet(expr.span) {
-                    return Some((sp, "consider removing the borrow", code));
+                    return Some((
+                        sp,
+                        "consider removing the borrow",
+                        code,
+                        Applicability::MachineApplicable,
+                    ));
                 }
             }
             (
                 _,
-                &ty::RawPtr(TypeAndMut { ty: _, mutbl: hir::Mutability::Not }),
-                &ty::Ref(_, _, hir::Mutability::Not),
+                &ty::RawPtr(TypeAndMut { ty: ty_b, mutbl: mutbl_b }),
+                &ty::Ref(_, ty_a, mutbl_a),
             ) => {
-                let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable);
-                // We don't ever need two-phase here since we throw out the result of the coercion
-                let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
-
-                if let Some(steps) =
-                    coerce.autoderef(sp, checked_ty).skip(1).find_map(|(referent_ty, steps)| {
-                        coerce
-                            .unify(
-                                coerce.tcx.mk_ptr(ty::TypeAndMut {
-                                    mutbl: hir::Mutability::Not,
-                                    ty: referent_ty,
-                                }),
-                                expected,
-                            )
-                            .ok()
-                            .map(|_| steps)
-                    })
-                {
-                    // The pointer type implements `Copy` trait so the suggestion is always valid.
-                    if let Ok(code) = sm.span_to_snippet(sp) {
-                        if code.starts_with('&') {
-                            let derefs = "*".repeat(steps - 1);
-                            let message = "consider dereferencing the reference";
-                            let suggestion = format!("&{}{}", derefs, code[1..].to_string());
-                            return Some((sp, message, suggestion));
+                if let Some(steps) = self.deref_steps(ty_a, ty_b) {
+                    // Only suggest valid if dereferencing needed.
+                    if steps > 0 {
+                        // The pointer type implements `Copy` trait so the suggestion is always valid.
+                        if let Ok(src) = sm.span_to_snippet(sp) {
+                            let derefs = &"*".repeat(steps);
+                            if let Some((src, applicability)) = match mutbl_b {
+                                hir::Mutability::Mut => {
+                                    let new_prefix = "&mut ".to_owned() + derefs;
+                                    match mutbl_a {
+                                        hir::Mutability::Mut => {
+                                            if let Some(s) =
+                                                self.replace_prefix(src, "&mut ", new_prefix)
+                                            {
+                                                Some((s, Applicability::MachineApplicable))
+                                            } else {
+                                                None
+                                            }
+                                        }
+                                        hir::Mutability::Not => {
+                                            if let Some(s) =
+                                                self.replace_prefix(src, "&", new_prefix)
+                                            {
+                                                Some((s, Applicability::Unspecified))
+                                            } else {
+                                                None
+                                            }
+                                        }
+                                    }
+                                }
+                                hir::Mutability::Not => {
+                                    let new_prefix = "&".to_owned() + derefs;
+                                    match mutbl_a {
+                                        hir::Mutability::Mut => {
+                                            if let Some(s) =
+                                                self.replace_prefix(src, "&mut ", new_prefix)
+                                            {
+                                                Some((s, Applicability::MachineApplicable))
+                                            } else {
+                                                None
+                                            }
+                                        }
+                                        hir::Mutability::Not => {
+                                            if let Some(s) =
+                                                self.replace_prefix(src, "&", new_prefix)
+                                            {
+                                                Some((s, Applicability::MachineApplicable))
+                                            } else {
+                                                None
+                                            }
+                                        }
+                                    }
+                                }
+                            } {
+                                return Some((sp, "consider dereferencing", src, applicability));
+                            }
                         }
                     }
                 }
@@ -616,7 +672,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         } else {
                             format!("*{}", code)
                         };
-                        return Some((sp, message, suggestion));
+                        return Some((sp, message, suggestion, Applicability::MachineApplicable));
                     }
                 }
             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c4317451988..6274a11ebd5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5036,8 +5036,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
     ) {
-        if let Some((sp, msg, suggestion)) = self.check_ref(expr, found, expected) {
-            err.span_suggestion(sp, msg, suggestion, Applicability::MachineApplicable);
+        if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
+            err.span_suggestion(sp, msg, suggestion, applicability);
         } else if let (ty::FnDef(def_id, ..), true) =
             (&found.kind, self.suggest_fn_call(err, expr, expected, found))
         {
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 1e6b6c430be..a3ee14e85d2 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -497,7 +497,7 @@ impl Drop for WaiterQueue<'_> {
             let mut queue = (state_and_queue & !STATE_MASK) as *const Waiter;
             while !queue.is_null() {
                 let next = (*queue).next;
-                let thread = (*queue).thread.replace(None).unwrap();
+                let thread = (*queue).thread.take().unwrap();
                 (*queue).signaled.store(true, Ordering::Release);
                 // ^- FIXME (maybe): This is another case of issue #55005
                 // `store()` has a potentially dangling ref to `signaled`.
diff --git a/src/test/run-make/wasm-panic-small/foo.rs b/src/test/run-make/wasm-panic-small/foo.rs
index fd3dddb18eb..6df52affe39 100644
--- a/src/test/run-make/wasm-panic-small/foo.rs
+++ b/src/test/run-make/wasm-panic-small/foo.rs
@@ -23,5 +23,5 @@ pub fn foo() {
 pub fn foo() -> usize {
     use std::cell::Cell;
     thread_local!(static A: Cell<Vec<u32>> = Cell::new(Vec::new()));
-    A.try_with(|x| x.replace(Vec::new()).len()).unwrap_or(0)
+    A.try_with(|x| x.take().len()).unwrap_or(0)
 }
diff --git a/src/test/ui/issues/issue-32122-1.stderr b/src/test/ui/issues/issue-32122-1.stderr
index 313de275c53..dfbd3223efc 100644
--- a/src/test/ui/issues/issue-32122-1.stderr
+++ b/src/test/ui/issues/issue-32122-1.stderr
@@ -5,7 +5,7 @@ LL |     let _: *const u8 = &a;
    |            ---------   ^^
    |            |           |
    |            |           expected `u8`, found struct `Foo`
-   |            |           help: consider dereferencing the reference: `&*a`
+   |            |           help: consider dereferencing: `&*a`
    |            expected due to this
    |
    = note: expected raw pointer `*const u8`
diff --git a/src/test/ui/issues/issue-32122-2.stderr b/src/test/ui/issues/issue-32122-2.stderr
index 959a49507e4..2e199e2a19f 100644
--- a/src/test/ui/issues/issue-32122-2.stderr
+++ b/src/test/ui/issues/issue-32122-2.stderr
@@ -5,7 +5,7 @@ LL |     let _: *const u8 = &a;
    |            ---------   ^^
    |            |           |
    |            |           expected `u8`, found struct `Emm`
-   |            |           help: consider dereferencing the reference: `&***a`
+   |            |           help: consider dereferencing: `&***a`
    |            expected due to this
    |
    = note: expected raw pointer `*const u8`
diff --git a/src/test/ui/issues/issue-71676-1.fixed b/src/test/ui/issues/issue-71676-1.fixed
new file mode 100644
index 00000000000..cbc0e8c061b
--- /dev/null
+++ b/src/test/ui/issues/issue-71676-1.fixed
@@ -0,0 +1,53 @@
+// run-rustfix
+use std::ops::Deref;
+use std::ops::DerefMut;
+struct Bar(u8);
+struct Foo(Bar);
+struct Emm(Foo);
+impl Deref for Bar{
+    type Target = u8;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Foo {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Emm {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl DerefMut for Bar{
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Foo {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Emm {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+fn main() {
+    // Suggest dereference with arbitrary mutability
+    let a = Emm(Foo(Bar(0)));
+    let _: *const u8 = &***a; //~ ERROR mismatched types
+
+    let mut a = Emm(Foo(Bar(0)));
+    let _: *mut u8 = &mut ***a; //~ ERROR mismatched types
+
+    let a = Emm(Foo(Bar(0)));
+    let _: *const u8 = &***a; //~ ERROR mismatched types
+
+    let mut a = Emm(Foo(Bar(0)));
+    let _: *mut u8 = &mut ***a; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/issues/issue-71676-1.rs b/src/test/ui/issues/issue-71676-1.rs
new file mode 100644
index 00000000000..6e87c7174c6
--- /dev/null
+++ b/src/test/ui/issues/issue-71676-1.rs
@@ -0,0 +1,53 @@
+// run-rustfix
+use std::ops::Deref;
+use std::ops::DerefMut;
+struct Bar(u8);
+struct Foo(Bar);
+struct Emm(Foo);
+impl Deref for Bar{
+    type Target = u8;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Foo {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Emm {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl DerefMut for Bar{
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Foo {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Emm {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+fn main() {
+    // Suggest dereference with arbitrary mutability
+    let a = Emm(Foo(Bar(0)));
+    let _: *const u8 = &a; //~ ERROR mismatched types
+
+    let mut a = Emm(Foo(Bar(0)));
+    let _: *mut u8 = &a; //~ ERROR mismatched types
+
+    let a = Emm(Foo(Bar(0)));
+    let _: *const u8 = &mut a; //~ ERROR mismatched types
+
+    let mut a = Emm(Foo(Bar(0)));
+    let _: *mut u8 = &mut a; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/issues/issue-71676-1.stderr b/src/test/ui/issues/issue-71676-1.stderr
new file mode 100644
index 00000000000..bbabc2202dc
--- /dev/null
+++ b/src/test/ui/issues/issue-71676-1.stderr
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-71676-1.rs:43:24
+   |
+LL |     let _: *const u8 = &a;
+   |            ---------   ^^
+   |            |           |
+   |            |           expected `u8`, found struct `Emm`
+   |            |           help: consider dereferencing: `&***a`
+   |            expected due to this
+   |
+   = note: expected raw pointer `*const u8`
+                found reference `&Emm`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71676-1.rs:46:22
+   |
+LL |     let _: *mut u8 = &a;
+   |            -------   ^^
+   |            |         |
+   |            |         types differ in mutability
+   |            |         help: consider dereferencing: `&mut ***a`
+   |            expected due to this
+   |
+   = note: expected raw pointer `*mut u8`
+                found reference `&Emm`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71676-1.rs:49:24
+   |
+LL |     let _: *const u8 = &mut a;
+   |            ---------   ^^^^^^
+   |            |           |
+   |            |           expected `u8`, found struct `Emm`
+   |            |           help: consider dereferencing: `&***a`
+   |            expected due to this
+   |
+   = note:    expected raw pointer `*const u8`
+           found mutable reference `&mut Emm`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71676-1.rs:52:22
+   |
+LL |     let _: *mut u8 = &mut a;
+   |            -------   ^^^^^^
+   |            |         |
+   |            |         expected `u8`, found struct `Emm`
+   |            |         help: consider dereferencing: `&mut ***a`
+   |            expected due to this
+   |
+   = note:    expected raw pointer `*mut u8`
+           found mutable reference `&mut Emm`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-71676-2.rs b/src/test/ui/issues/issue-71676-2.rs
new file mode 100644
index 00000000000..f3183899dc5
--- /dev/null
+++ b/src/test/ui/issues/issue-71676-2.rs
@@ -0,0 +1,42 @@
+use std::ops::Deref;
+use std::ops::DerefMut;
+struct Bar(u8);
+struct Foo(Bar);
+struct Emm(Foo);
+impl Deref for Bar{
+    type Target = u8;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Foo {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Emm {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl DerefMut for Bar{
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Foo {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Emm {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+fn main() {
+    let a = Emm(Foo(Bar(0)));
+    let _: *mut u8 = &a; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/issues/issue-71676-2.stderr b/src/test/ui/issues/issue-71676-2.stderr
new file mode 100644
index 00000000000..ebdd345809a
--- /dev/null
+++ b/src/test/ui/issues/issue-71676-2.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-71676-2.rs:41:22
+   |
+LL |     let _: *mut u8 = &a;
+   |            -------   ^^
+   |            |         |
+   |            |         types differ in mutability
+   |            |         help: consider dereferencing: `&mut ***a`
+   |            expected due to this
+   |
+   = note: expected raw pointer `*mut u8`
+                found reference `&Emm`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
index ce9b02b6d82..0c328a2594a 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
@@ -1,146 +1,152 @@
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:22:13
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:17:20
    |
-LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left with overflow
+LL |     const N: i32 = T::N << 42;
+   |                    ^^^^^^^^^^ attempt to shift left with overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:9:9
+  --> $DIR/lint-exceeding-bitshifts.rs:8:9
    |
-LL | #![deny(arithmetic_overflow, const_err)]
+LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:27:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:21:13
+   |
+LL |     let _ = x << 42;
+   |             ^^^^^^^ attempt to shift left with overflow
+
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:26:15
    |
 LL |       let n = 1u8 << 8;
    |               ^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:29:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:28:15
    |
 LL |       let n = 1u16 << 16;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:31:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:30:15
    |
 LL |       let n = 1u32 << 32;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:33:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:32:15
    |
 LL |       let n = 1u64 << 64;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:35:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:34:15
    |
 LL |       let n = 1i8 << 8;
    |               ^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:37:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:36:15
    |
 LL |       let n = 1i16 << 16;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:39:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:38:15
    |
 LL |       let n = 1i32 << 32;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:41:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:40:15
    |
 LL |       let n = 1i64 << 64;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:44:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:43:15
    |
 LL |       let n = 1u8 >> 8;
    |               ^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:46:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:45:15
    |
 LL |       let n = 1u16 >> 16;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:48:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:47:15
    |
 LL |       let n = 1u32 >> 32;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:50:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:49:15
    |
 LL |       let n = 1u64 >> 64;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:52:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:51:15
    |
 LL |       let n = 1i8 >> 8;
    |               ^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:54:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:53:15
    |
 LL |       let n = 1i16 >> 16;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:56:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:55:15
    |
 LL |       let n = 1i32 >> 32;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:58:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:57:15
    |
 LL |       let n = 1i64 >> 64;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:62:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:61:15
    |
 LL |       let n = n << 8;
    |               ^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:64:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:63:15
    |
 LL |       let n = 1u8 << -8;
    |               ^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:69:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:68:15
    |
 LL |       let n = 1u8 << (4+4);
    |               ^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:71:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:70:15
    |
 LL |       let n = 1i64 >> [64][0];
    |               ^^^^^^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:77:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:76:15
    |
 LL |       let n = 1_isize << BITS;
    |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:78:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_usize << BITS;
    |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: aborting due to 23 previous errors
+warning: 24 warnings emitted
 
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
index ce9b02b6d82..0c328a2594a 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
@@ -1,146 +1,152 @@
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:22:13
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:17:20
    |
-LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left with overflow
+LL |     const N: i32 = T::N << 42;
+   |                    ^^^^^^^^^^ attempt to shift left with overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:9:9
+  --> $DIR/lint-exceeding-bitshifts.rs:8:9
    |
-LL | #![deny(arithmetic_overflow, const_err)]
+LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:27:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:21:13
+   |
+LL |     let _ = x << 42;
+   |             ^^^^^^^ attempt to shift left with overflow
+
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:26:15
    |
 LL |       let n = 1u8 << 8;
    |               ^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:29:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:28:15
    |
 LL |       let n = 1u16 << 16;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:31:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:30:15
    |
 LL |       let n = 1u32 << 32;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:33:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:32:15
    |
 LL |       let n = 1u64 << 64;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:35:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:34:15
    |
 LL |       let n = 1i8 << 8;
    |               ^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:37:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:36:15
    |
 LL |       let n = 1i16 << 16;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:39:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:38:15
    |
 LL |       let n = 1i32 << 32;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:41:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:40:15
    |
 LL |       let n = 1i64 << 64;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:44:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:43:15
    |
 LL |       let n = 1u8 >> 8;
    |               ^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:46:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:45:15
    |
 LL |       let n = 1u16 >> 16;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:48:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:47:15
    |
 LL |       let n = 1u32 >> 32;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:50:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:49:15
    |
 LL |       let n = 1u64 >> 64;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:52:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:51:15
    |
 LL |       let n = 1i8 >> 8;
    |               ^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:54:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:53:15
    |
 LL |       let n = 1i16 >> 16;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:56:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:55:15
    |
 LL |       let n = 1i32 >> 32;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:58:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:57:15
    |
 LL |       let n = 1i64 >> 64;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:62:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:61:15
    |
 LL |       let n = n << 8;
    |               ^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:64:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:63:15
    |
 LL |       let n = 1u8 << -8;
    |               ^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:69:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:68:15
    |
 LL |       let n = 1u8 << (4+4);
    |               ^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:71:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:70:15
    |
 LL |       let n = 1i64 >> [64][0];
    |               ^^^^^^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:77:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:76:15
    |
 LL |       let n = 1_isize << BITS;
    |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:78:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_usize << BITS;
    |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: aborting due to 23 previous errors
+warning: 24 warnings emitted
 
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
index ce9b02b6d82..0c328a2594a 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
@@ -1,146 +1,152 @@
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:22:13
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:17:20
    |
-LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left with overflow
+LL |     const N: i32 = T::N << 42;
+   |                    ^^^^^^^^^^ attempt to shift left with overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:9:9
+  --> $DIR/lint-exceeding-bitshifts.rs:8:9
    |
-LL | #![deny(arithmetic_overflow, const_err)]
+LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:27:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:21:13
+   |
+LL |     let _ = x << 42;
+   |             ^^^^^^^ attempt to shift left with overflow
+
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:26:15
    |
 LL |       let n = 1u8 << 8;
    |               ^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:29:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:28:15
    |
 LL |       let n = 1u16 << 16;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:31:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:30:15
    |
 LL |       let n = 1u32 << 32;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:33:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:32:15
    |
 LL |       let n = 1u64 << 64;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:35:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:34:15
    |
 LL |       let n = 1i8 << 8;
    |               ^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:37:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:36:15
    |
 LL |       let n = 1i16 << 16;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:39:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:38:15
    |
 LL |       let n = 1i32 << 32;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:41:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:40:15
    |
 LL |       let n = 1i64 << 64;
    |               ^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:44:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:43:15
    |
 LL |       let n = 1u8 >> 8;
    |               ^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:46:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:45:15
    |
 LL |       let n = 1u16 >> 16;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:48:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:47:15
    |
 LL |       let n = 1u32 >> 32;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:50:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:49:15
    |
 LL |       let n = 1u64 >> 64;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:52:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:51:15
    |
 LL |       let n = 1i8 >> 8;
    |               ^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:54:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:53:15
    |
 LL |       let n = 1i16 >> 16;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:56:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:55:15
    |
 LL |       let n = 1i32 >> 32;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:58:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:57:15
    |
 LL |       let n = 1i64 >> 64;
    |               ^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:62:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:61:15
    |
 LL |       let n = n << 8;
    |               ^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:64:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:63:15
    |
 LL |       let n = 1u8 << -8;
    |               ^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:69:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:68:15
    |
 LL |       let n = 1u8 << (4+4);
    |               ^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:71:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:70:15
    |
 LL |       let n = 1i64 >> [64][0];
    |               ^^^^^^^^^^^^^^^ attempt to shift right with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:77:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:76:15
    |
 LL |       let n = 1_isize << BITS;
    |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:78:15
+warning: this arithmetic operation will overflow
+  --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_usize << BITS;
    |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
 
-error: aborting due to 23 previous errors
+warning: 24 warnings emitted
 
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs
index 7deee5320a8..565bef49c9f 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.rs
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs
@@ -2,11 +2,10 @@
 //[noopt]compile-flags: -C opt-level=0
 //[opt]compile-flags: -O
 //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O
-
-// build-fail
+// build-pass
 
 #![crate_type="lib"]
-#![deny(arithmetic_overflow, const_err)]
+#![warn(arithmetic_overflow, const_err)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
 
@@ -15,65 +14,65 @@ pub trait Foo {
 }
 
 impl<T: Foo> Foo for Vec<T> {
-    const N: i32 = T::N << 42; // FIXME this should warn
+    const N: i32 = T::N << 42; //~ WARN: arithmetic operation will overflow
 }
 
 pub fn foo(x: i32) {
-    let _ = x << 42; //~ ERROR: arithmetic operation will overflow
+    let _ = x << 42; //~ WARN: arithmetic operation will overflow
 }
 
 pub fn main() {
       let n = 1u8 << 7;
-      let n = 1u8 << 8;   //~ ERROR: arithmetic operation will overflow
+      let n = 1u8 << 8;   //~ WARN: arithmetic operation will overflow
       let n = 1u16 << 15;
-      let n = 1u16 << 16; //~ ERROR: arithmetic operation will overflow
+      let n = 1u16 << 16; //~ WARN: arithmetic operation will overflow
       let n = 1u32 << 31;
-      let n = 1u32 << 32; //~ ERROR: arithmetic operation will overflow
+      let n = 1u32 << 32; //~ WARN: arithmetic operation will overflow
       let n = 1u64 << 63;
-      let n = 1u64 << 64; //~ ERROR: arithmetic operation will overflow
+      let n = 1u64 << 64; //~ WARN: arithmetic operation will overflow
       let n = 1i8 << 7;
-      let n = 1i8 << 8;   //~ ERROR: arithmetic operation will overflow
+      let n = 1i8 << 8;   //~ WARN: arithmetic operation will overflow
       let n = 1i16 << 15;
-      let n = 1i16 << 16; //~ ERROR: arithmetic operation will overflow
+      let n = 1i16 << 16; //~ WARN: arithmetic operation will overflow
       let n = 1i32 << 31;
-      let n = 1i32 << 32; //~ ERROR: arithmetic operation will overflow
+      let n = 1i32 << 32; //~ WARN: arithmetic operation will overflow
       let n = 1i64 << 63;
-      let n = 1i64 << 64; //~ ERROR: arithmetic operation will overflow
+      let n = 1i64 << 64; //~ WARN: arithmetic operation will overflow
 
       let n = 1u8 >> 7;
-      let n = 1u8 >> 8;   //~ ERROR: arithmetic operation will overflow
+      let n = 1u8 >> 8;   //~ WARN: arithmetic operation will overflow
       let n = 1u16 >> 15;
-      let n = 1u16 >> 16; //~ ERROR: arithmetic operation will overflow
+      let n = 1u16 >> 16; //~ WARN: arithmetic operation will overflow
       let n = 1u32 >> 31;
-      let n = 1u32 >> 32; //~ ERROR: arithmetic operation will overflow
+      let n = 1u32 >> 32; //~ WARN: arithmetic operation will overflow
       let n = 1u64 >> 63;
-      let n = 1u64 >> 64; //~ ERROR: arithmetic operation will overflow
+      let n = 1u64 >> 64; //~ WARN: arithmetic operation will overflow
       let n = 1i8 >> 7;
-      let n = 1i8 >> 8;   //~ ERROR: arithmetic operation will overflow
+      let n = 1i8 >> 8;   //~ WARN: arithmetic operation will overflow
       let n = 1i16 >> 15;
-      let n = 1i16 >> 16; //~ ERROR: arithmetic operation will overflow
+      let n = 1i16 >> 16; //~ WARN: arithmetic operation will overflow
       let n = 1i32 >> 31;
-      let n = 1i32 >> 32; //~ ERROR: arithmetic operation will overflow
+      let n = 1i32 >> 32; //~ WARN: arithmetic operation will overflow
       let n = 1i64 >> 63;
-      let n = 1i64 >> 64; //~ ERROR: arithmetic operation will overflow
+      let n = 1i64 >> 64; //~ WARN: arithmetic operation will overflow
 
       let n = 1u8;
       let n = n << 7;
-      let n = n << 8; //~ ERROR: arithmetic operation will overflow
+      let n = n << 8; //~ WARN: arithmetic operation will overflow
 
-      let n = 1u8 << -8; //~ ERROR: arithmetic operation will overflow
+      let n = 1u8 << -8; //~ WARN: arithmetic operation will overflow
 
       let n = 1i8<<(1isize+-1);
 
       let n = 1u8 << (4+3);
-      let n = 1u8 << (4+4); //~ ERROR: arithmetic operation will overflow
+      let n = 1u8 << (4+4); //~ WARN: arithmetic operation will overflow
       let n = 1i64 >> [63][0];
-      let n = 1i64 >> [64][0]; //~ ERROR: arithmetic operation will overflow
+      let n = 1i64 >> [64][0]; //~ WARN: arithmetic operation will overflow
 
       #[cfg(target_pointer_width = "32")]
       const BITS: usize = 32;
       #[cfg(target_pointer_width = "64")]
       const BITS: usize = 64;
-      let n = 1_isize << BITS; //~ ERROR: arithmetic operation will overflow
-      let n = 1_usize << BITS; //~ ERROR: arithmetic operation will overflow
+      let n = 1_isize << BITS; //~ WARN: arithmetic operation will overflow
+      let n = 1_usize << BITS; //~ WARN: arithmetic operation will overflow
 }
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
index d0ca1705037..3c5da3f1440 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -108,4 +108,5 @@ LL | fn deprecated_without_unstable_or_stable() { }
 
 error: aborting due to 18 previous errors
 
-For more information about this error, try `rustc --explain E0541`.
+Some errors have detailed explanations: E0539, E0541.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs
index 499ac461e59..a5b85646581 100644
--- a/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs
+++ b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs
@@ -7,7 +7,7 @@ struct MyType<'a>(Cell<Option<&'a mut MyType<'a>>>, PhantomPinned);
 impl<'a> Clone for &'a mut MyType<'a> {
     //~^ ERROR E0751
     fn clone(&self) -> &'a mut MyType<'a> {
-        self.0.replace(None).unwrap()
+        self.0.take().unwrap()
     }
 }
 
diff --git a/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs
index 245be800780..606cc65a84b 100644
--- a/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs
+++ b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs
@@ -12,7 +12,7 @@ struct MyType<'a>(Cell<Option<&'a mut MyType<'a>>>, PhantomPinned);
 impl<'a> DerefMut for &'a MyType<'a> {
     //~^ ERROR E0751
     fn deref_mut(&mut self) -> &mut MyType<'a> {
-        self.0.replace(None).unwrap()
+        self.0.take().unwrap()
     }
 }