about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs17
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl2
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs7
-rw-r--r--compiler/rustc_driver_impl/src/signal_handler.rs20
-rw-r--r--compiler/rustc_lint/src/default_could_be_derived.rs34
-rw-r--r--compiler/rustc_parse_format/src/lib.rs35
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs198
-rw-r--r--library/panic_unwind/src/seh.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs140
-rw-r--r--tests/ui/borrowck/index-mut-help.stderr11
-rw-r--r--tests/ui/btreemap/btreemap-index-mut-2.stderr6
-rw-r--r--tests/ui/btreemap/btreemap-index-mut.stderr6
-rw-r--r--tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed25
-rw-r--r--tests/ui/fmt/suggest-wrongly-order-format-parameter.rs25
-rw-r--r--tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr35
-rw-r--r--tests/ui/hashmap/hashmap-index-mut.stderr6
-rw-r--r--tests/ui/issues/issue-41726.stderr5
-rw-r--r--tests/ui/no_send-rc.stderr4
-rw-r--r--tests/ui/structs/manual-default-impl-could-be-derived.stderr5
-rw-r--r--tests/ui/suggestions/issue-84973-blacklist.stderr4
-rw-r--r--tests/ui/traits/suggest-dereferences/deref-argument.fixed37
-rw-r--r--tests/ui/traits/suggest-dereferences/deref-argument.rs37
-rw-r--r--tests/ui/traits/suggest-dereferences/deref-argument.stderr39
24 files changed, 482 insertions, 229 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 2484f817a06..c690789b587 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -575,7 +575,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         // ---------- place
                         self.err.multipart_suggestions(
                             format!(
-                                "to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
+                                "use `.insert()` to insert a value into a `{}`, `.get_mut()` \
+                                to modify it, or the entry API for more flexibility",
                                 self.ty,
                             ),
                             vec![
@@ -592,16 +593,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                     (rv.span.shrink_to_hi(), ")".to_string()),
                                 ],
                                 vec![
-                                    // val.get_mut(index).map(|v| { *v = rv; });
+                                    // if let Some(v) = val.get_mut(index) { *v = rv; }
+                                    (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
                                     (
                                         val.span.shrink_to_hi().with_hi(index.span.lo()),
                                         ".get_mut(".to_string(),
                                     ),
                                     (
                                         index.span.shrink_to_hi().with_hi(place.span.hi()),
-                                        ").map(|val| { *val".to_string(),
+                                        ") { *val".to_string(),
                                     ),
-                                    (rv.span.shrink_to_hi(), "; })".to_string()),
+                                    (rv.span.shrink_to_hi(), "; }".to_string()),
                                 ],
                                 vec![
                                     // let x = val.entry(index).or_insert(rv);
@@ -622,21 +624,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         self.suggested = true;
                     } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
                         && let hir::ExprKind::Index(val, index, _) = receiver.kind
-                        && expr.span == self.assign_span
+                        && receiver.span == self.assign_span
                     {
                         // val[index].path(args..);
                         self.err.multipart_suggestion(
                             format!("to modify a `{}` use `.get_mut()`", self.ty),
                             vec![
+                                (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
                                 (
                                     val.span.shrink_to_hi().with_hi(index.span.lo()),
                                     ".get_mut(".to_string(),
                                 ),
                                 (
                                     index.span.shrink_to_hi().with_hi(receiver.span.hi()),
-                                    ").map(|val| val".to_string(),
+                                    ") { val".to_string(),
                                 ),
-                                (sp.shrink_to_hi(), ")".to_string()),
+                                (sp.shrink_to_hi(), "; }".to_string()),
                             ],
                             Applicability::MachineApplicable,
                         );
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 7a31d2a2239..4cac7cb93f5 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -197,6 +197,8 @@ builtin_macros_format_redundant_args = redundant {$n ->
 
 builtin_macros_format_remove_raw_ident = remove the `r#`
 
+builtin_macros_format_reorder_format_parameter = did you mean `{$replacement}`?
+
 builtin_macros_format_requires_string = requires at least a format string argument
 
 builtin_macros_format_string_invalid = invalid format string: {$desc}
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 1abdfdb9c65..6213bd802c7 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -618,6 +618,17 @@ pub(crate) enum InvalidFormatStringSuggestion {
         #[primary_span]
         span: Span,
     },
+    #[suggestion(
+        builtin_macros_format_reorder_format_parameter,
+        code = "{replacement}",
+        style = "verbose",
+        applicability = "machine-applicable"
+    )]
+    ReorderFormatParameter {
+        #[primary_span]
+        span: Span,
+        replacement: String,
+    },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 0112499c509..5202fe26c40 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -321,6 +321,13 @@ fn make_format_args(
                     e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
                 }
             }
+            parse::Suggestion::ReorderFormatParameter(span, replacement) => {
+                let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
+                e.sugg_ = Some(errors::InvalidFormatStringSuggestion::ReorderFormatParameter {
+                    span,
+                    replacement,
+                });
+            }
         }
         let guar = ecx.dcx().emit_err(e);
         return ExpandResult::Ready(Err(guar));
diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs
index d4f8199390c..08b7d937661 100644
--- a/compiler/rustc_driver_impl/src/signal_handler.rs
+++ b/compiler/rustc_driver_impl/src/signal_handler.rs
@@ -2,7 +2,7 @@
 //! Primarily used to extract a backtrace from stack overflow
 
 use std::alloc::{Layout, alloc};
-use std::{fmt, mem, ptr};
+use std::{fmt, mem, ptr, slice};
 
 use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
 
@@ -35,20 +35,22 @@ macro raw_errln($tokens:tt) {
 }
 
 /// Signal handler installed for SIGSEGV
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#[allow(static_mut_refs)]
-extern "C" fn print_stack_trace(_: libc::c_int) {
+///
+/// # Safety
+///
+/// Caller must ensure that this function is not re-entered.
+unsafe extern "C" fn print_stack_trace(_: libc::c_int) {
     const MAX_FRAMES: usize = 256;
-    // Reserve data segment so we don't have to malloc in a signal handler, which might fail
-    // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
-    static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES];
     let stack = unsafe {
+        // Reserve data segment so we don't have to malloc in a signal handler, which might fail
+        // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
+        static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES];
         // Collect return addresses
-        let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32);
+        let depth = libc::backtrace(&raw mut STACK_TRACE as _, MAX_FRAMES as i32);
         if depth == 0 {
             return;
         }
-        &STACK_TRACE.as_slice()[0..(depth as _)]
+        slice::from_raw_parts(&raw const STACK_TRACE as _, depth as _)
     };
 
     // Just a stack trace is cryptic. Explain what we're doing.
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index d95cbb05158..bae9defa687 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -1,9 +1,11 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::Diag;
+use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_middle::ty;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::Symbol;
+use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
 
 use crate::{LateContext, LateLintPass};
@@ -149,13 +151,16 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
         let hir_id = cx.tcx.local_def_id_to_hir_id(local);
         let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return };
         cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| {
-            mk_lint(diag, orig_fields, fields);
+            mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields);
         });
     }
 }
 
 fn mk_lint(
+    tcx: TyCtxt<'_>,
     diag: &mut Diag<'_, ()>,
+    type_def_id: DefId,
+    impl_def_id: DefId,
     orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>,
     fields: &[hir::ExprField<'_>],
 ) {
@@ -175,11 +180,24 @@ fn mk_lint(
         }
     }
 
-    diag.help(if removed_all_fields {
-        "to avoid divergence in behavior between `Struct { .. }` and \
-         `<Struct as Default>::default()`, derive the `Default`"
+    if removed_all_fields {
+        let msg = "to avoid divergence in behavior between `Struct { .. }` and \
+                   `<Struct as Default>::default()`, derive the `Default`";
+        if let Some(hir::Node::Item(impl_)) = tcx.hir().get_if_local(impl_def_id) {
+            diag.multipart_suggestion_verbose(
+                msg,
+                vec![
+                    (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()),
+                    (impl_.span, String::new()),
+                ],
+                Applicability::MachineApplicable,
+            );
+        } else {
+            diag.help(msg);
+        }
     } else {
-        "use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them \
-         diverging over time"
-    });
+        let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \
+                   avoid them diverging over time";
+        diag.help(msg);
+    }
 }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 1716f417969..9eb335cb34c 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -221,6 +221,11 @@ pub enum Suggestion {
     /// Remove `r#` from identifier:
     /// `format!("{r#foo}")` -> `format!("{foo}")`
     RemoveRawIdent(InnerSpan),
+    /// Reorder format parameter:
+    /// `format!("{foo:?#}")` -> `format!("{foo:#?}")`
+    /// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
+    /// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
+    ReorderFormatParameter(InnerSpan, string::String),
 }
 
 /// The parser structure for interpreting the input format string. This is
@@ -731,6 +736,12 @@ impl<'a> Parser<'a> {
             }
         } else if self.consume('?') {
             spec.ty = "?";
+            if let Some(&(_, maybe)) = self.cur.peek() {
+                match maybe {
+                    '#' | 'x' | 'X' => self.suggest_format_parameter(maybe),
+                    _ => (),
+                }
+            }
         } else {
             spec.ty = self.word();
             if !spec.ty.is_empty() {
@@ -932,6 +943,30 @@ impl<'a> Parser<'a> {
             }
         }
     }
+
+    fn suggest_format_parameter(&mut self, c: char) {
+        let replacement = match c {
+            '#' => "#?",
+            'x' => "x?",
+            'X' => "X?",
+            _ => return,
+        };
+        let Some(pos) = self.consume_pos(c) else {
+            return;
+        };
+
+        let span = self.span(pos - 1, pos + 1);
+        let pos = self.to_span_index(pos);
+
+        self.errors.insert(0, ParseError {
+            description: format!("expected `}}`, found `{c}`"),
+            note: None,
+            label: "expected `'}'`".into(),
+            span: pos.to(pos),
+            secondary_label: None,
+            suggestion: Suggestion::ReorderFormatParameter(span, format!("{replacement}")),
+        })
+    }
 }
 
 /// Finds the indices of all characters that have been processed and differ between the actual
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 6a8f7f4ee35..1b8b35f18df 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -445,9 +445,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    /// When after several dereferencing, the reference satisfies the trait
-    /// bound. This function provides dereference suggestion for this
-    /// specific situation.
+    /// Provide a suggestion to dereference arguments to functions and binary operators, if that
+    /// would satisfy trait bounds.
     pub(super) fn suggest_dereferences(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -461,127 +460,100 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)
         {
             // Suggest dereferencing the argument to a function/method call if possible
+
+            // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)
             let mut real_trait_pred = trait_pred;
             while let Some((parent_code, parent_trait_pred)) = code.parent() {
                 code = parent_code;
                 if let Some(parent_trait_pred) = parent_trait_pred {
                     real_trait_pred = parent_trait_pred;
                 }
+            }
 
-                // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle
-                // `ReBound`, and we don't particularly care about the regions.
-                let real_ty =
-                    self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty());
+            // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle
+            // `ReBound`, and we don't particularly care about the regions.
+            let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty());
+            if !self.can_eq(obligation.param_env, real_ty, arg_ty) {
+                return false;
+            }
 
-                if self.can_eq(obligation.param_env, real_ty, arg_ty)
-                    && let ty::Ref(region, base_ty, mutbl) = *real_ty.kind()
+            // Potentially, we'll want to place our dereferences under a `&`. We don't try this for
+            // `&mut`, since we can't be sure users will get the side-effects they want from it.
+            // If this doesn't work, we'll try removing the `&` in `suggest_remove_reference`.
+            // FIXME(dianne): this misses the case where users need both to deref and remove `&`s.
+            // This method could be combined with `TypeErrCtxt::suggest_remove_reference` to handle
+            // that, similar to what `FnCtxt::suggest_deref_or_ref` does.
+            let (is_under_ref, base_ty, span) = match expr.kind {
+                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, subexpr)
+                    if let &ty::Ref(region, base_ty, hir::Mutability::Not) = real_ty.kind() =>
                 {
-                    let autoderef = (self.autoderef_steps)(base_ty);
-                    if let Some(steps) =
-                        autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| {
-                            // Re-add the `&`
-                            let ty = Ty::new_ref(self.tcx, region, ty, mutbl);
-
-                            // Remapping bound vars here
-                            let real_trait_pred_and_ty = real_trait_pred
-                                .map_bound(|inner_trait_pred| (inner_trait_pred, ty));
-                            let obligation = self.mk_trait_obligation_with_new_self_ty(
-                                obligation.param_env,
-                                real_trait_pred_and_ty,
-                            );
-                            let may_hold = obligations
-                                .iter()
-                                .chain([&obligation])
-                                .all(|obligation| self.predicate_may_hold(obligation))
-                                .then_some(steps);
+                    (Some(region), base_ty, subexpr.span)
+                }
+                // Don't suggest `*&mut`, etc.
+                hir::ExprKind::AddrOf(..) => return false,
+                _ => (None, real_ty, obligation.cause.span),
+            };
 
-                            may_hold
-                        })
-                    {
-                        if steps > 0 {
-                            // Don't care about `&mut` because `DerefMut` is used less
-                            // often and user will not expect that an autoderef happens.
-                            if let hir::Node::Expr(hir::Expr {
-                                kind:
-                                    hir::ExprKind::AddrOf(
-                                        hir::BorrowKind::Ref,
-                                        hir::Mutability::Not,
-                                        expr,
-                                    ),
-                                ..
-                            }) = self.tcx.hir_node(*arg_hir_id)
-                            {
-                                let derefs = "*".repeat(steps);
-                                err.span_suggestion_verbose(
-                                    expr.span.shrink_to_lo(),
-                                    "consider dereferencing here",
-                                    derefs,
-                                    Applicability::MachineApplicable,
-                                );
-                                return true;
-                            }
-                        }
-                    } else if real_trait_pred != trait_pred {
-                        // This branch addresses #87437.
-
-                        let span = obligation.cause.span;
-                        // Remapping bound vars here
-                        let real_trait_pred_and_base_ty = real_trait_pred
-                            .map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
-                        let obligation = self.mk_trait_obligation_with_new_self_ty(
-                            obligation.param_env,
-                            real_trait_pred_and_base_ty,
-                        );
-                        let sized_obligation = Obligation::new(
-                            self.tcx,
-                            obligation.cause.clone(),
-                            obligation.param_env,
-                            ty::TraitRef::new(
-                                self.tcx,
-                                self.tcx.require_lang_item(
-                                    hir::LangItem::Sized,
-                                    Some(obligation.cause.span),
-                                ),
-                                [base_ty],
-                            ),
-                        );
-                        if self.predicate_may_hold(&obligation)
-                            && self.predicate_must_hold_modulo_regions(&sized_obligation)
-                            // Do not suggest * if it is already a reference,
-                            // will suggest removing the borrow instead in that case.
-                            && !matches!(expr.kind, hir::ExprKind::AddrOf(..))
-                        {
-                            let call_node = self.tcx.hir_node(*call_hir_id);
-                            let msg = "consider dereferencing here";
-                            let is_receiver = matches!(
-                                call_node,
-                                Node::Expr(hir::Expr {
-                                    kind: hir::ExprKind::MethodCall(_, receiver_expr, ..),
-                                    ..
-                                })
-                                if receiver_expr.hir_id == *arg_hir_id
-                            );
-                            if is_receiver {
-                                err.multipart_suggestion_verbose(
-                                    msg,
-                                    vec![
-                                        (span.shrink_to_lo(), "(*".to_string()),
-                                        (span.shrink_to_hi(), ")".to_string()),
-                                    ],
-                                    Applicability::MachineApplicable,
-                                )
-                            } else {
-                                err.span_suggestion_verbose(
-                                    span.shrink_to_lo(),
-                                    msg,
-                                    '*',
-                                    Applicability::MachineApplicable,
-                                )
-                            };
-                            return true;
-                        }
-                    }
+            let autoderef = (self.autoderef_steps)(base_ty);
+            let mut is_boxed = base_ty.is_box();
+            if let Some(steps) = autoderef.into_iter().position(|(mut ty, obligations)| {
+                // Ensure one of the following for dereferencing to be valid: we're passing by
+                // reference, `ty` is `Copy`, or we're moving out of a (potentially nested) `Box`.
+                let can_deref = is_under_ref.is_some()
+                    || self.type_is_copy_modulo_regions(obligation.param_env, ty)
+                    || ty.is_numeric() // for inference vars (presumably but not provably `Copy`)
+                    || is_boxed && self.type_is_sized_modulo_regions(obligation.param_env, ty);
+                is_boxed &= ty.is_box();
+
+                // Re-add the `&` if necessary
+                if let Some(region) = is_under_ref {
+                    ty = Ty::new_ref(self.tcx, region, ty, hir::Mutability::Not);
                 }
+
+                // Remapping bound vars here
+                let real_trait_pred_and_ty =
+                    real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
+                let obligation = self.mk_trait_obligation_with_new_self_ty(
+                    obligation.param_env,
+                    real_trait_pred_and_ty,
+                );
+
+                can_deref
+                    && obligations
+                        .iter()
+                        .chain([&obligation])
+                        .all(|obligation| self.predicate_may_hold(obligation))
+            }) && steps > 0
+            {
+                let derefs = "*".repeat(steps);
+                let msg = "consider dereferencing here";
+                let call_node = self.tcx.hir_node(*call_hir_id);
+                let is_receiver = matches!(
+                    call_node,
+                    Node::Expr(hir::Expr {
+                        kind: hir::ExprKind::MethodCall(_, receiver_expr, ..),
+                        ..
+                    })
+                    if receiver_expr.hir_id == *arg_hir_id
+                );
+                if is_receiver {
+                    err.multipart_suggestion_verbose(
+                        msg,
+                        vec![
+                            (span.shrink_to_lo(), format!("({derefs}")),
+                            (span.shrink_to_hi(), ")".to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    )
+                } else {
+                    err.span_suggestion_verbose(
+                        span.shrink_to_lo(),
+                        msg,
+                        derefs,
+                        Applicability::MachineApplicable,
+                    )
+                };
+                return true;
             }
         } else if let (
             ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id: Some(rhs_hir_id), .. },
diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs
index 565a2b8c573..5afa0a19756 100644
--- a/library/panic_unwind/src/seh.rs
+++ b/library/panic_unwind/src/seh.rs
@@ -288,8 +288,6 @@ cfg_if::cfg_if! {
    }
 }
 
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#[allow(static_mut_refs)]
 pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     use core::intrinsics::atomic_store_seqcst;
 
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index b4d37b25a6c..9434d876df8 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -401,12 +401,13 @@ impl Step for RustAnalyzer {
 
 macro_rules! tool_check_step {
     (
-        $name:ident,
-        $display_name:literal,
-        $path:literal,
-        $($alias:literal, )*
-        $source_type:path
-        $(, $default:literal )?
+        $name:ident {
+            // The part of this path after the final '/' is also used as a display name.
+            path: $path:literal
+            $(, alt_path: $alt_path:literal )*
+            $(, default: $default:literal )?
+            $( , )?
+        }
     ) => {
         #[derive(Debug, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
@@ -416,11 +417,11 @@ macro_rules! tool_check_step {
         impl Step for $name {
             type Output = ();
             const ONLY_HOSTS: bool = true;
-            /// don't ever check out-of-tree tools by default, they'll fail when toolstate is broken
-            const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;
+            /// Most of the tool-checks using this macro are run by default.
+            const DEFAULT: bool = true $( && $default )?;
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-                run.paths(&[ $path, $($alias),* ])
+                run.paths(&[ $path, $( $alt_path ),* ])
             }
 
             fn make_run(run: RunConfig<'_>) {
@@ -428,82 +429,71 @@ macro_rules! tool_check_step {
             }
 
             fn run(self, builder: &Builder<'_>) {
-                let compiler = builder.compiler(builder.top_stage, builder.config.build);
-                let target = self.target;
-
-                builder.ensure(Rustc::new(target, builder));
-
-                let mut cargo = prepare_tool_cargo(
-                    builder,
-                    compiler,
-                    Mode::ToolRustc,
-                    target,
-                    builder.kind,
-                    $path,
-                    $source_type,
-                    &[],
-                );
-
-                // For ./x.py clippy, don't run with --all-targets because
-                // linting tests and benchmarks can produce very noisy results
-                if builder.kind != Kind::Clippy {
-                    cargo.arg("--all-targets");
-                }
-
-                let _guard = builder.msg_check(&format!("{} artifacts", $display_name), target);
-                run_cargo(
-                    builder,
-                    cargo,
-                    builder.config.free_args.clone(),
-                    &stamp(builder, compiler, target),
-                    vec![],
-                    true,
-                    false,
-                );
-
-                /// Cargo's output path in a given stage, compiled by a particular
-                /// compiler for the specified target.
-                fn stamp(
-                    builder: &Builder<'_>,
-                    compiler: Compiler,
-                    target: TargetSelection,
-                ) -> PathBuf {
-                    builder
-                        .cargo_out(compiler, Mode::ToolRustc, target)
-                        .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
-                }
+                let Self { target } = self;
+                run_tool_check_step(builder, target, stringify!($name), $path);
             }
         }
-    };
+    }
+}
+
+/// Used by the implementation of `Step::run` in `tool_check_step!`.
+fn run_tool_check_step(
+    builder: &Builder<'_>,
+    target: TargetSelection,
+    step_type_name: &str,
+    path: &str,
+) {
+    let display_name = path.rsplit('/').next().unwrap();
+    let compiler = builder.compiler(builder.top_stage, builder.config.build);
+
+    builder.ensure(Rustc::new(target, builder));
+
+    let mut cargo = prepare_tool_cargo(
+        builder,
+        compiler,
+        Mode::ToolRustc,
+        target,
+        builder.kind,
+        path,
+        // Currently, all of the tools that use this macro/function are in-tree.
+        // If support for out-of-tree tools is re-added in the future, those
+        // steps should probably be marked non-default so that the default
+        // checks aren't affected by toolstate being broken.
+        SourceType::InTree,
+        &[],
+    );
+
+    // For ./x.py clippy, don't run with --all-targets because
+    // linting tests and benchmarks can produce very noisy results
+    if builder.kind != Kind::Clippy {
+        cargo.arg("--all-targets");
+    }
+
+    let stamp = builder
+        .cargo_out(compiler, Mode::ToolRustc, target)
+        .join(format!(".{}-check.stamp", step_type_name.to_lowercase()));
+
+    let _guard = builder.msg_check(format!("{display_name} artifacts"), target);
+    run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
 }
 
-tool_check_step!(Rustdoc, "rustdoc", "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
+tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc" });
 // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
 // of a submodule. Since the SourceType only drives the deny-warnings
 // behavior, treat it as in-tree so that any new warnings in clippy will be
 // rejected.
-tool_check_step!(Clippy, "clippy", "src/tools/clippy", SourceType::InTree);
-tool_check_step!(Miri, "miri", "src/tools/miri", SourceType::InTree);
-tool_check_step!(CargoMiri, "cargo-miri", "src/tools/miri/cargo-miri", SourceType::InTree);
-tool_check_step!(Rls, "rls", "src/tools/rls", SourceType::InTree);
-tool_check_step!(Rustfmt, "rustfmt", "src/tools/rustfmt", SourceType::InTree);
-tool_check_step!(
-    MiroptTestTools,
-    "miropt-test-tools",
-    "src/tools/miropt-test-tools",
-    SourceType::InTree
-);
-tool_check_step!(
-    TestFloatParse,
-    "test-float-parse",
-    "src/etc/test-float-parse",
-    SourceType::InTree
-);
-
-tool_check_step!(Bootstrap, "bootstrap", "src/bootstrap", SourceType::InTree, false);
+tool_check_step!(Clippy { path: "src/tools/clippy" });
+tool_check_step!(Miri { path: "src/tools/miri" });
+tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri" });
+tool_check_step!(Rls { path: "src/tools/rls" });
+tool_check_step!(Rustfmt { path: "src/tools/rustfmt" });
+tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" });
+tool_check_step!(TestFloatParse { path: "src/etc/test-float-parse" });
+
+tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
 // Compiletest is implicitly "checked" when it gets built in order to run tests,
 // so this is mainly for people working on compiletest to run locally.
-tool_check_step!(Compiletest, "compiletest", "src/tools/compiletest", SourceType::InTree, false);
+tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false });
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
diff --git a/tests/ui/borrowck/index-mut-help.stderr b/tests/ui/borrowck/index-mut-help.stderr
index fde2b5dc076..c4c9c1c5313 100644
--- a/tests/ui/borrowck/index-mut-help.stderr
+++ b/tests/ui/borrowck/index-mut-help.stderr
@@ -5,7 +5,10 @@ LL |     map["peter"].clear();
    |     ^^^^^^^^^^^^ cannot borrow as mutable
    |
    = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
-   = help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
+help: to modify a `HashMap<&str, String>` use `.get_mut()`
+   |
+LL |     if let Some(val) = map.get_mut("peter") { val.clear(); };
+   |     ++++++++++++++++++    ~~~~~~~~~       ~~~~~~~        +++
 
 error[E0594]: cannot assign to data in an index of `HashMap<&str, String>`
   --> $DIR/index-mut-help.rs:11:5
@@ -14,12 +17,12 @@ LL |     map["peter"] = "0".to_string();
    |     ^^^^^^^^^^^^ cannot assign
    |
    = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
-help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
+help: use `.insert()` to insert a value into a `HashMap<&str, String>`, `.get_mut()` to modify it, or the entry API for more flexibility
    |
 LL |     map.insert("peter", "0".to_string());
    |        ~~~~~~~~       ~                +
-LL |     map.get_mut("peter").map(|val| { *val = "0".to_string(); });
-   |        ~~~~~~~~~       ~~~~~~~~~~~~~~~~~~                  ++++
+LL |     if let Some(val) = map.get_mut("peter") { *val = "0".to_string(); };
+   |     ++++++++++++++++++    ~~~~~~~~~       ~~~~~~~~                  +++
 LL |     let val = map.entry("peter").or_insert("0".to_string());
    |     +++++++++    ~~~~~~~       ~~~~~~~~~~~~               +
 
diff --git a/tests/ui/btreemap/btreemap-index-mut-2.stderr b/tests/ui/btreemap/btreemap-index-mut-2.stderr
index 0b8c77cb9e1..c42462ee1eb 100644
--- a/tests/ui/btreemap/btreemap-index-mut-2.stderr
+++ b/tests/ui/btreemap/btreemap-index-mut-2.stderr
@@ -5,12 +5,12 @@ LL |         map[&0] = 1;
    |         ^^^^^^^^^^^ cannot assign
    |
    = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap<u32, u32>`
-help: to modify a `BTreeMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
+help: use `.insert()` to insert a value into a `BTreeMap<u32, u32>`, `.get_mut()` to modify it, or the entry API for more flexibility
    |
 LL |         map.insert(&0, 1);
    |            ~~~~~~~~  ~  +
-LL |         map.get_mut(&0).map(|val| { *val = 1; });
-   |            ~~~~~~~~~  ~~~~~~~~~~~~~~~~~~    ++++
+LL |         if let Some(val) = map.get_mut(&0) { *val = 1; };
+   |         ++++++++++++++++++    ~~~~~~~~~  ~~~~~~~~    +++
 LL |         let val = map.entry(&0).or_insert(1);
    |         +++++++++    ~~~~~~~  ~~~~~~~~~~~~ +
 
diff --git a/tests/ui/btreemap/btreemap-index-mut.stderr b/tests/ui/btreemap/btreemap-index-mut.stderr
index cc465fbf3de..f402f503c15 100644
--- a/tests/ui/btreemap/btreemap-index-mut.stderr
+++ b/tests/ui/btreemap/btreemap-index-mut.stderr
@@ -5,12 +5,12 @@ LL |     map[&0] = 1;
    |     ^^^^^^^^^^^ cannot assign
    |
    = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap<u32, u32>`
-help: to modify a `BTreeMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
+help: use `.insert()` to insert a value into a `BTreeMap<u32, u32>`, `.get_mut()` to modify it, or the entry API for more flexibility
    |
 LL |     map.insert(&0, 1);
    |        ~~~~~~~~  ~  +
-LL |     map.get_mut(&0).map(|val| { *val = 1; });
-   |        ~~~~~~~~~  ~~~~~~~~~~~~~~~~~~    ++++
+LL |     if let Some(val) = map.get_mut(&0) { *val = 1; };
+   |     ++++++++++++++++++    ~~~~~~~~~  ~~~~~~~~    +++
 LL |     let val = map.entry(&0).or_insert(1);
    |     +++++++++    ~~~~~~~  ~~~~~~~~~~~~ +
 
diff --git a/tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed b/tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed
new file mode 100644
index 00000000000..a080a65854a
--- /dev/null
+++ b/tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed
@@ -0,0 +1,25 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/129966
+//!
+//! Ensure we provide suggestion for wrongly ordered format parameters.
+
+//@ run-rustfix
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct Foo(u8, u8);
+
+fn main() {
+    let f = Foo(1, 2);
+
+    println!("{f:#?}");
+    //~^ ERROR invalid format string: expected `}`, found `#`
+    //~| HELP did you mean `#?`?
+
+    println!("{f:x?}");
+    //~^ ERROR invalid format string: expected `}`, found `x`
+    //~| HELP did you mean `x?`?
+
+    println!("{f:X?}");
+    //~^ ERROR invalid format string: expected `}`, found `X`
+    //~| HELP did you mean `X?`?
+}
diff --git a/tests/ui/fmt/suggest-wrongly-order-format-parameter.rs b/tests/ui/fmt/suggest-wrongly-order-format-parameter.rs
new file mode 100644
index 00000000000..830dafd4479
--- /dev/null
+++ b/tests/ui/fmt/suggest-wrongly-order-format-parameter.rs
@@ -0,0 +1,25 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/129966
+//!
+//! Ensure we provide suggestion for wrongly ordered format parameters.
+
+//@ run-rustfix
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct Foo(u8, u8);
+
+fn main() {
+    let f = Foo(1, 2);
+
+    println!("{f:?#}");
+    //~^ ERROR invalid format string: expected `}`, found `#`
+    //~| HELP did you mean `#?`?
+
+    println!("{f:?x}");
+    //~^ ERROR invalid format string: expected `}`, found `x`
+    //~| HELP did you mean `x?`?
+
+    println!("{f:?X}");
+    //~^ ERROR invalid format string: expected `}`, found `X`
+    //~| HELP did you mean `X?`?
+}
diff --git a/tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr b/tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr
new file mode 100644
index 00000000000..fe693d2e904
--- /dev/null
+++ b/tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr
@@ -0,0 +1,35 @@
+error: invalid format string: expected `}`, found `#`
+  --> $DIR/suggest-wrongly-order-format-parameter.rs:14:19
+   |
+LL |     println!("{f:?#}");
+   |                   ^ expected `'}'` in format string
+   |
+help: did you mean `#?`?
+   |
+LL |     println!("{f:#?}");
+   |                  ~~
+
+error: invalid format string: expected `}`, found `x`
+  --> $DIR/suggest-wrongly-order-format-parameter.rs:18:19
+   |
+LL |     println!("{f:?x}");
+   |                   ^ expected `'}'` in format string
+   |
+help: did you mean `x?`?
+   |
+LL |     println!("{f:x?}");
+   |                  ~~
+
+error: invalid format string: expected `}`, found `X`
+  --> $DIR/suggest-wrongly-order-format-parameter.rs:22:19
+   |
+LL |     println!("{f:?X}");
+   |                   ^ expected `'}'` in format string
+   |
+help: did you mean `X?`?
+   |
+LL |     println!("{f:X?}");
+   |                  ~~
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/hashmap/hashmap-index-mut.stderr b/tests/ui/hashmap/hashmap-index-mut.stderr
index 2381b8ecb96..ad33c6f9b15 100644
--- a/tests/ui/hashmap/hashmap-index-mut.stderr
+++ b/tests/ui/hashmap/hashmap-index-mut.stderr
@@ -5,12 +5,12 @@ LL |     map[&0] = 1;
    |     ^^^^^^^^^^^ cannot assign
    |
    = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<u32, u32>`
-help: to modify a `HashMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
+help: use `.insert()` to insert a value into a `HashMap<u32, u32>`, `.get_mut()` to modify it, or the entry API for more flexibility
    |
 LL |     map.insert(&0, 1);
    |        ~~~~~~~~  ~  +
-LL |     map.get_mut(&0).map(|val| { *val = 1; });
-   |        ~~~~~~~~~  ~~~~~~~~~~~~~~~~~~    ++++
+LL |     if let Some(val) = map.get_mut(&0) { *val = 1; };
+   |     ++++++++++++++++++    ~~~~~~~~~  ~~~~~~~~    +++
 LL |     let val = map.entry(&0).or_insert(1);
    |     +++++++++    ~~~~~~~  ~~~~~~~~~~~~ +
 
diff --git a/tests/ui/issues/issue-41726.stderr b/tests/ui/issues/issue-41726.stderr
index fe7d4df7067..250bba222bf 100644
--- a/tests/ui/issues/issue-41726.stderr
+++ b/tests/ui/issues/issue-41726.stderr
@@ -5,7 +5,10 @@ LL |         things[src.as_str()].sort();
    |         ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
    |
    = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<String, Vec<String>>`
-   = help: to modify a `HashMap<String, Vec<String>>`, use `.get_mut()`, `.insert()` or the entry API
+help: to modify a `HashMap<String, Vec<String>>` use `.get_mut()`
+   |
+LL |         if let Some(val) = things.get_mut(src.as_str()) { val.sort(); };
+   |         ++++++++++++++++++       ~~~~~~~~~            ~~~~~~~       +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/no_send-rc.stderr b/tests/ui/no_send-rc.stderr
index 3534167870b..1430a7a29ea 100644
--- a/tests/ui/no_send-rc.stderr
+++ b/tests/ui/no_send-rc.stderr
@@ -12,6 +12,10 @@ note: required by a bound in `bar`
    |
 LL | fn bar<T: Send>(_: T) {}
    |           ^^^^ required by this bound in `bar`
+help: consider dereferencing here
+   |
+LL |     bar(*x);
+   |         +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/structs/manual-default-impl-could-be-derived.stderr b/tests/ui/structs/manual-default-impl-could-be-derived.stderr
index e8f607fac7e..cf06d5418e1 100644
--- a/tests/ui/structs/manual-default-impl-could-be-derived.stderr
+++ b/tests/ui/structs/manual-default-impl-could-be-derived.stderr
@@ -31,7 +31,10 @@ LL | |             y: 0,
 LL | | }
    | |_^
    |
-   = help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default`
+help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default`
+   |
+LL ~ #[derive(Default)] struct B {
+   |
 
 error: `Default` impl doesn't use the declared default field values
   --> $DIR/manual-default-impl-could-be-derived.rs:43:1
diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr
index a6324a824c1..3db400418c7 100644
--- a/tests/ui/suggestions/issue-84973-blacklist.stderr
+++ b/tests/ui/suggestions/issue-84973-blacklist.stderr
@@ -86,6 +86,10 @@ note: required by a bound in `f_send`
    |
 LL | fn f_send<T: Send>(t: T) {}
    |              ^^^^ required by this bound in `f_send`
+help: consider dereferencing here
+   |
+LL |     f_send(*rc);
+   |            +
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/traits/suggest-dereferences/deref-argument.fixed b/tests/ui/traits/suggest-dereferences/deref-argument.fixed
new file mode 100644
index 00000000000..8235ae0b628
--- /dev/null
+++ b/tests/ui/traits/suggest-dereferences/deref-argument.fixed
@@ -0,0 +1,37 @@
+//@ run-rustfix
+//! diagnostic test for #90997.
+//! test that E0277 suggests dereferences to satisfy bounds when the referent is `Copy` or boxed.
+use std::ops::Deref;
+
+trait Test {
+    fn test(self);
+}
+fn consume_test(x: impl Test) { x.test() }
+
+impl Test for u32 {
+    fn test(self) {}
+}
+struct MyRef(u32);
+impl Deref for MyRef {
+    type Target = u32;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+struct NonCopy;
+impl Test for NonCopy {
+    fn test(self) {}
+}
+
+fn main() {
+    let my_ref = MyRef(0);
+    consume_test(*my_ref);
+    //~^ ERROR the trait bound `MyRef: Test` is not satisfied
+    //~| SUGGESTION *
+
+    let nested_box = Box::new(Box::new(Box::new(NonCopy)));
+    consume_test(***nested_box);
+    //~^ ERROR the trait bound `Box<Box<Box<NonCopy>>>: Test` is not satisfied
+    //~| SUGGESTION ***
+}
diff --git a/tests/ui/traits/suggest-dereferences/deref-argument.rs b/tests/ui/traits/suggest-dereferences/deref-argument.rs
new file mode 100644
index 00000000000..2f96b75c4e4
--- /dev/null
+++ b/tests/ui/traits/suggest-dereferences/deref-argument.rs
@@ -0,0 +1,37 @@
+//@ run-rustfix
+//! diagnostic test for #90997.
+//! test that E0277 suggests dereferences to satisfy bounds when the referent is `Copy` or boxed.
+use std::ops::Deref;
+
+trait Test {
+    fn test(self);
+}
+fn consume_test(x: impl Test) { x.test() }
+
+impl Test for u32 {
+    fn test(self) {}
+}
+struct MyRef(u32);
+impl Deref for MyRef {
+    type Target = u32;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+struct NonCopy;
+impl Test for NonCopy {
+    fn test(self) {}
+}
+
+fn main() {
+    let my_ref = MyRef(0);
+    consume_test(my_ref);
+    //~^ ERROR the trait bound `MyRef: Test` is not satisfied
+    //~| SUGGESTION *
+
+    let nested_box = Box::new(Box::new(Box::new(NonCopy)));
+    consume_test(nested_box);
+    //~^ ERROR the trait bound `Box<Box<Box<NonCopy>>>: Test` is not satisfied
+    //~| SUGGESTION ***
+}
diff --git a/tests/ui/traits/suggest-dereferences/deref-argument.stderr b/tests/ui/traits/suggest-dereferences/deref-argument.stderr
new file mode 100644
index 00000000000..3dc92fd6ab6
--- /dev/null
+++ b/tests/ui/traits/suggest-dereferences/deref-argument.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `MyRef: Test` is not satisfied
+  --> $DIR/deref-argument.rs:29:18
+   |
+LL |     consume_test(my_ref);
+   |     ------------ ^^^^^^ the trait `Test` is not implemented for `MyRef`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `consume_test`
+  --> $DIR/deref-argument.rs:9:25
+   |
+LL | fn consume_test(x: impl Test) { x.test() }
+   |                         ^^^^ required by this bound in `consume_test`
+help: consider dereferencing here
+   |
+LL |     consume_test(*my_ref);
+   |                  +
+
+error[E0277]: the trait bound `Box<Box<Box<NonCopy>>>: Test` is not satisfied
+  --> $DIR/deref-argument.rs:34:18
+   |
+LL |     consume_test(nested_box);
+   |     ------------ ^^^^^^^^^^ the trait `Test` is not implemented for `Box<Box<Box<NonCopy>>>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `consume_test`
+  --> $DIR/deref-argument.rs:9:25
+   |
+LL | fn consume_test(x: impl Test) { x.test() }
+   |                         ^^^^ required by this bound in `consume_test`
+help: consider dereferencing here
+   |
+LL |     consume_test(***nested_box);
+   |                  +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.