about summary refs log tree commit diff
diff options
context:
space:
mode:
authoryukang <moorekang@gmail.com>2022-09-23 15:28:48 +0800
committeryukang <moorekang@gmail.com>2022-09-26 07:56:26 +0800
commit672e3f4d77f8b9f86a999992b459a95909aa74c2 (patch)
treedc760065aa30e12057f6eafbabf6f81a9228efc5
parent11bb80a92b4f46fa7dfa9148d0bdfc185a7621bd (diff)
fix #102087, Suggest Default::default() when binding isn't initialized
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs70
-rw-r--r--src/test/ui/asm/aarch64/type-check-2-2.stderr10
-rw-r--r--src/test/ui/asm/x86_64/type-check-5.stderr10
-rw-r--r--src/test/ui/borrowck/borrowck-block-unint.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit-2.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fru.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-op-equal.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-plus-equal.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-return.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-storage-dead.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-after-item.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-field-access.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr50
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr15
-rw-r--r--src/test/ui/borrowck/borrowck-uninit.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr10
-rw-r--r--src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-while-cond.stderr5
-rw-r--r--src/test/ui/borrowck/issue-24267-flow-exit.stderr8
-rw-r--r--src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr5
-rw-r--r--src/test/ui/borrowck/suggest-assign-rvalue.rs57
-rw-r--r--src/test/ui/borrowck/suggest-assign-rvalue.stderr138
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr5
-rw-r--r--src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr5
-rw-r--r--src/test/ui/consts/issue-78655.stderr5
-rw-r--r--src/test/ui/drop/repeat-drop-2.stderr5
-rw-r--r--src/test/ui/loops/loop-proper-liveness.stderr4
-rw-r--r--src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr5
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.stderr10
-rw-r--r--src/test/ui/moves/move-into-dead-array-1.stderr5
-rw-r--r--src/test/ui/moves/move-of-addr-of-mut.stderr4
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.stderr5
-rw-r--r--src/test/ui/nll/match-on-borrowed.stderr5
-rw-r--r--src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr5
38 files changed, 514 insertions, 0 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 69ad7f66275..3182656b6aa 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -369,6 +369,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
         visitor.visit_body(&body);
 
+        let mut show_assign_sugg = false;
         let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
         | InitializationRequiringAction::Assignment = desired_action
         {
@@ -396,6 +397,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             .count()
             == 0
         {
+            show_assign_sugg = true;
             "isn't initialized"
         } else {
             "is possibly-uninitialized"
@@ -446,10 +448,78 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
             }
         }
+
         err.span_label(decl_span, "binding declared here but left uninitialized");
+        if show_assign_sugg {
+            struct LetVisitor {
+                decl_span: Span,
+                sugg_span: Option<Span>,
+            }
+
+            impl<'v> Visitor<'v> for LetVisitor {
+                fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+                    if self.sugg_span.is_some() {
+                        return;
+                    }
+                    if let hir::StmtKind::Local(hir::Local {
+                            span, ty, init: None, ..
+                        }) = &ex.kind && span.contains(self.decl_span) {
+                            self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
+                    }
+                    hir::intravisit::walk_stmt(self, ex);
+                }
+            }
+
+            let mut visitor = LetVisitor { decl_span, sugg_span: None };
+            visitor.visit_body(&body);
+            if let Some(span) = visitor.sugg_span {
+                self.suggest_assign_value(&mut err, moved_place, span);
+            }
+        }
         err
     }
 
+    fn suggest_assign_value(
+        &self,
+        err: &mut Diagnostic,
+        moved_place: PlaceRef<'tcx>,
+        sugg_span: Span,
+    ) {
+        let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
+        debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
+
+        let tcx = self.infcx.tcx;
+        let implements_default = |ty, param_env| {
+            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+                return false;
+            };
+            tcx.infer_ctxt().enter(|infcx| {
+                infcx
+                    .type_implements_trait(default_trait, ty, ty::List::empty(), param_env)
+                    .may_apply()
+            })
+        };
+
+        let assign_value = match ty.kind() {
+            ty::Bool => "false",
+            ty::Float(_) => "0.0",
+            ty::Int(_) | ty::Uint(_) => "0",
+            ty::Never | ty::Error(_) => "",
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
+            ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
+            _ => "todo!()",
+        };
+
+        if !assign_value.is_empty() {
+            err.span_suggestion_verbose(
+                sugg_span.shrink_to_hi(),
+                format!("consider assigning a value"),
+                format!(" = {}", assign_value),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     fn suggest_borrow_fn_like(
         &self,
         err: &mut Diagnostic,
diff --git a/src/test/ui/asm/aarch64/type-check-2-2.stderr b/src/test/ui/asm/aarch64/type-check-2-2.stderr
index b2a695529f9..eef16a165a8 100644
--- a/src/test/ui/asm/aarch64/type-check-2-2.stderr
+++ b/src/test/ui/asm/aarch64/type-check-2-2.stderr
@@ -5,6 +5,11 @@ LL |         let x: u64;
    |             - binding declared here but left uninitialized
 LL |         asm!("{}", in(reg) x);
    |                            ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let x: u64 = 0;
+   |                    +++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-2-2.rs:22:9
@@ -13,6 +18,11 @@ LL |         let mut y: u64;
    |             ----- binding declared here but left uninitialized
 LL |         asm!("{}", inout(reg) y);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let mut y: u64 = 0;
+   |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-2-2.rs:30:29
diff --git a/src/test/ui/asm/x86_64/type-check-5.stderr b/src/test/ui/asm/x86_64/type-check-5.stderr
index e9c93fea561..bd90461e52c 100644
--- a/src/test/ui/asm/x86_64/type-check-5.stderr
+++ b/src/test/ui/asm/x86_64/type-check-5.stderr
@@ -5,6 +5,11 @@ LL |         let x: u64;
    |             - binding declared here but left uninitialized
 LL |         asm!("{}", in(reg) x);
    |                            ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let x: u64 = 0;
+   |                    +++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-5.rs:18:9
@@ -13,6 +18,11 @@ LL |         let mut y: u64;
    |             ----- binding declared here but left uninitialized
 LL |         asm!("{}", inout(reg) y);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let mut y: u64 = 0;
+   |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-5.rs:26:29
diff --git a/src/test/ui/borrowck/borrowck-block-unint.stderr b/src/test/ui/borrowck/borrowck-block-unint.stderr
index e720db1c696..f47921a9752 100644
--- a/src/test/ui/borrowck/borrowck-block-unint.stderr
+++ b/src/test/ui/borrowck/borrowck-block-unint.stderr
@@ -7,6 +7,11 @@ LL |     force(|| {
    |           ^^ `x` used here but it isn't initialized
 LL |         println!("{}", x);
    |                        - borrow occurs due to use in closure
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
index 91038b3adca..ea93a8f409c 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
@@ -8,6 +8,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-break-uninit.stderr b/src/test/ui/borrowck/borrowck-break-uninit.stderr
index 8d0c9582fda..a7a8fc2ff83 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit.stderr
@@ -8,6 +8,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
index e8a2fbc91ea..1a22b5f0975 100644
--- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
@@ -5,6 +5,11 @@ LL |         let i: isize;
    |             - binding declared here but left uninitialized
 LL |         i
    |         ^ `i` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let i: isize = 0;
+   |                      +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
index 1e950d6a20d..f1b9b9aa709 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
@@ -5,6 +5,11 @@ LL |         let i: isize;
    |             - binding declared here but left uninitialized
 LL |         i
    |         ^ `i` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let i: isize = 0;
+   |                      +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.stderr
index 83a3e3e0e3a..39b28811a0c 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fru.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-fru.stderr
@@ -5,6 +5,11 @@ LL |     let mut origin: Point;
    |         ---------- binding declared here but left uninitialized
 LL |     origin = Point { x: 10, ..origin };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^ `origin.y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut origin: Point = todo!();
+   |                           +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.stderr b/src/test/ui/borrowck/borrowck-init-op-equal.stderr
index 74704b2abfe..ef0fa6df4fb 100644
--- a/src/test/ui/borrowck/borrowck-init-op-equal.stderr
+++ b/src/test/ui/borrowck/borrowck-init-op-equal.stderr
@@ -5,6 +5,11 @@ LL |     let v: isize;
    |         - binding declared here but left uninitialized
 LL |     v += 1;
    |     ^^^^^^ `v` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let v: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
index 7542576d636..cec05331836 100644
--- a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
+++ b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
@@ -5,6 +5,11 @@ LL |     let mut v: isize;
    |         ----- binding declared here but left uninitialized
 LL |     v = v + 1;
    |         ^ `v` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut v: isize = 0;
+   |                      +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-return.stderr b/src/test/ui/borrowck/borrowck-return.stderr
index 1c916e22317..9799357c9ca 100644
--- a/src/test/ui/borrowck/borrowck-return.stderr
+++ b/src/test/ui/borrowck/borrowck-return.stderr
@@ -5,6 +5,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     return x;
    |            ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr
index 2cea4392d6a..3a413153acd 100644
--- a/src/test/ui/borrowck/borrowck-storage-dead.stderr
+++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr
@@ -5,6 +5,11 @@ LL |         let x: i32;
    |             - binding declared here but left uninitialized
 LL |         let _ = x + 1;
    |                 ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let x: i32 = 0;
+   |                    +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
index 588b1b0c972..071598b42ee 100644
--- a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
@@ -6,6 +6,11 @@ LL |     let bar;
 LL |     fn baz(_x: isize) { }
 LL |     baz(bar);
    |         ^^^ `bar` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let bar = 0;
+   |             +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
index 6a38a798919..f0f4ad704b7 100644
--- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
@@ -5,6 +5,11 @@ LL |     let mut a: Point;
    |         ----- binding declared here but left uninitialized
 LL |     let _ = a.x + 1;
    |             ^^^ `a.x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut a: Point = Default::default();
+   |                      ++++++++++++++++++++
 
 error[E0382]: use of moved value: `line1.origin`
   --> $DIR/borrowck-uninit-field-access.rs:25:13
diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
index 744cb14e662..fdbb451bde4 100644
--- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
@@ -5,6 +5,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x += 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:9:5
@@ -13,6 +18,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x -= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:12:5
@@ -21,6 +31,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x *= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:15:5
@@ -29,6 +44,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x /= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:18:5
@@ -37,6 +57,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x %= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:21:5
@@ -45,6 +70,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x ^= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:24:5
@@ -53,6 +83,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x &= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:27:5
@@ -61,6 +96,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x |= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:30:5
@@ -69,6 +109,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x <<= 1;
    |     ^^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:33:5
@@ -77,6 +122,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x >>= 1;
    |     ^^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
index c486cb6dd0c..73fded7545c 100644
--- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
@@ -5,6 +5,11 @@ LL |     let x: &&Box<i32>;
    |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
    |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&Box<i32> = todo!();
+   |                       +++++++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:11:14
@@ -13,6 +18,11 @@ LL |     let x: &&S<i32, i32>;
    |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
    |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&S<i32, i32> = todo!();
+   |                          +++++++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:14:14
@@ -21,6 +31,11 @@ LL |     let x: &&i32;
    |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
    |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&i32 = todo!();
+   |                  +++++++++
 
 error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:18:5
diff --git a/src/test/ui/borrowck/borrowck-uninit.stderr b/src/test/ui/borrowck/borrowck-uninit.stderr
index d5566691a82..eeafc4ce191 100644
--- a/src/test/ui/borrowck/borrowck-uninit.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit.stderr
@@ -5,6 +5,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     foo(x);
    |         ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
index 459cf1398b7..18e808f10d0 100644
--- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
+++ b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
@@ -5,6 +5,11 @@ LL |     let w: &mut [isize];
    |         - binding declared here but left uninitialized
 LL |     w[5] = 0;
    |     ^^^^ `*w` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let w: &mut [isize] = todo!();
+   |                         +++++++++
 
 error[E0381]: used binding `w` isn't initialized
   --> $DIR/borrowck-use-in-index-lvalue.rs:6:5
@@ -13,6 +18,11 @@ LL |     let mut w: &mut [isize];
    |         ----- binding declared here but left uninitialized
 LL |     w[5] = 0;
    |     ^^^^ `*w` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut w: &mut [isize] = todo!();
+   |                             +++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
index 942ed4fc6ca..55f3ff553c1 100644
--- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
+++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
@@ -5,6 +5,11 @@ LL |     let x: &i32;
    |         - binding declared here but left uninitialized
 LL |     let y = x as *const dyn Foo;
    |             ^ `*x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &i32 = todo!();
+   |                 +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
index f3289e23981..ea3d0d3ef51 100644
--- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
+++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
@@ -5,6 +5,11 @@ LL |     let x: &i32;
    |         - binding declared here but left uninitialized
 LL |     let y = x as *const i32;
    |             ^ `*x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &i32 = todo!();
+   |                 +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-while-cond.stderr b/src/test/ui/borrowck/borrowck-while-cond.stderr
index e41c1c55e60..5d019498956 100644
--- a/src/test/ui/borrowck/borrowck-while-cond.stderr
+++ b/src/test/ui/borrowck/borrowck-while-cond.stderr
@@ -5,6 +5,11 @@ LL |     let x: bool;
    |         - binding declared here but left uninitialized
 LL |     while x { }
    |           ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: bool = false;
+   |                 +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-24267-flow-exit.stderr b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
index b85e8f216e5..58d1c8c0f73 100644
--- a/src/test/ui/borrowck/issue-24267-flow-exit.stderr
+++ b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
@@ -8,6 +8,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/issue-24267-flow-exit.rs:18:20
@@ -19,6 +23,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
index f5d2eecfa91..9683da919aa 100644
--- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
+++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
@@ -5,6 +5,11 @@ LL |     let e: i32;
    |         - binding declared here but left uninitialized
 LL |     match e {
    |           ^ `e` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let e: i32 = 0;
+   |                +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/suggest-assign-rvalue.rs b/src/test/ui/borrowck/suggest-assign-rvalue.rs
new file mode 100644
index 00000000000..aaca9d47f0a
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-assign-rvalue.rs
@@ -0,0 +1,57 @@
+#![allow(dead_code)]
+#![feature(never_type)]
+
+#[derive(Debug, Default)]
+struct Demo {}
+
+#[derive(Debug)]
+struct DemoNoDef {}
+
+fn apple(_: u32) {}
+
+fn banana() {
+    let chaenomeles;
+    apple(chaenomeles);
+    //~^ ERROR used binding `chaenomeles` isn't initialized [E0381]
+}
+
+fn main() {
+    let my_bool: bool = bool::default();
+    println!("my_bool: {}", my_bool);
+
+    let my_float: f32;
+    println!("my_float: {}", my_float);
+    //~^ ERROR used binding `my_float` isn't initialized
+    let demo: Demo;
+    println!("demo: {:?}", demo);
+    //~^ ERROR used binding `demo` isn't initialized
+
+    let demo_no: DemoNoDef;
+    println!("demo_no: {:?}", demo_no);
+    //~^ ERROR used binding `demo_no` isn't initialized
+
+    let arr: [i32; 5];
+    println!("arr: {:?}", arr);
+    //~^ ERROR used binding `arr` isn't initialized
+    let foo: Vec<&str>;
+    println!("foo: {:?}", foo);
+    //~^ ERROR used binding `foo` isn't initialized
+
+    let my_string: String;
+    println!("my_string: {}", my_string);
+    //~^ ERROR used binding `my_string` isn't initialized
+
+    let my_int: &i32;
+    println!("my_int: {}", *my_int);
+    //~^ ERROR used binding `my_int` isn't initialized
+
+    let hello: &str;
+    println!("hello: {}", hello);
+    //~^ ERROR used binding `hello` isn't initialized
+
+    let never: !;
+    println!("never: {}", never);
+    //~^ ERROR used binding `never` isn't initialized [E0381]
+
+    banana();
+}
diff --git a/src/test/ui/borrowck/suggest-assign-rvalue.stderr b/src/test/ui/borrowck/suggest-assign-rvalue.stderr
new file mode 100644
index 00000000000..92acba640d7
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-assign-rvalue.stderr
@@ -0,0 +1,138 @@
+error[E0381]: used binding `chaenomeles` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:14:11
+   |
+LL |     let chaenomeles;
+   |         ----------- binding declared here but left uninitialized
+LL |     apple(chaenomeles);
+   |           ^^^^^^^^^^^ `chaenomeles` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let chaenomeles = 0;
+   |                     +++
+
+error[E0381]: used binding `my_float` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:23:30
+   |
+LL |     let my_float: f32;
+   |         -------- binding declared here but left uninitialized
+LL |     println!("my_float: {}", my_float);
+   |                              ^^^^^^^^ `my_float` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_float: f32 = 0.0;
+   |                       +++++
+
+error[E0381]: used binding `demo` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:26:28
+   |
+LL |     let demo: Demo;
+   |         ---- binding declared here but left uninitialized
+LL |     println!("demo: {:?}", demo);
+   |                            ^^^^ `demo` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let demo: Demo = Default::default();
+   |                    ++++++++++++++++++++
+
+error[E0381]: used binding `demo_no` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:30:31
+   |
+LL |     let demo_no: DemoNoDef;
+   |         ------- binding declared here but left uninitialized
+LL |     println!("demo_no: {:?}", demo_no);
+   |                               ^^^^^^^ `demo_no` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let demo_no: DemoNoDef = todo!();
+   |                            +++++++++
+
+error[E0381]: used binding `arr` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:34:27
+   |
+LL |     let arr: [i32; 5];
+   |         --- binding declared here but left uninitialized
+LL |     println!("arr: {:?}", arr);
+   |                           ^^^ `arr` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let arr: [i32; 5] = todo!();
+   |                       +++++++++
+
+error[E0381]: used binding `foo` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:37:27
+   |
+LL |     let foo: Vec<&str>;
+   |         --- binding declared here but left uninitialized
+LL |     println!("foo: {:?}", foo);
+   |                           ^^^ `foo` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let foo: Vec<&str> = vec![];
+   |                        ++++++++
+
+error[E0381]: used binding `my_string` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:41:31
+   |
+LL |     let my_string: String;
+   |         --------- binding declared here but left uninitialized
+LL |     println!("my_string: {}", my_string);
+   |                               ^^^^^^^^^ `my_string` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_string: String = Default::default();
+   |                           ++++++++++++++++++++
+
+error[E0381]: used binding `my_int` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:45:28
+   |
+LL |     let my_int: &i32;
+   |         ------ binding declared here but left uninitialized
+LL |     println!("my_int: {}", *my_int);
+   |                            ^^^^^^^ `*my_int` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_int: &i32 = todo!();
+   |                      +++++++++
+
+error[E0381]: used binding `hello` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:49:27
+   |
+LL |     let hello: &str;
+   |         ----- binding declared here but left uninitialized
+LL |     println!("hello: {}", hello);
+   |                           ^^^^^ `hello` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let hello: &str = todo!();
+   |                     +++++++++
+
+error[E0381]: used binding `never` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:53:27
+   |
+LL |     let never: !;
+   |         ----- binding declared here but left uninitialized
+LL |     println!("never: {}", never);
+   |                           ^^^^^ `never` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index fea5441ec67..ad061d93cb2 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -76,6 +76,11 @@ LL |     let x: u8;
    |         - binding declared here but left uninitialized
 LL |     let c1 = || match x { };
    |                       ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: u8 = 0;
+   |               +++
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
index c62f1d1d230..0ed370b83c5 100644
--- a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
+++ b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
@@ -5,6 +5,11 @@ LL |     let s: &'static str; s.len()
    |         -                ^^^^^^^ `*s` used here but it isn't initialized
    |         |
    |         binding declared here but left uninitialized
+   |
+help: consider assigning a value
+   |
+LL |     let s: &'static str = todo!(); s.len()
+   |                         +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-78655.stderr b/src/test/ui/consts/issue-78655.stderr
index f5b1123e7f3..6b83fa0e5a0 100644
--- a/src/test/ui/consts/issue-78655.stderr
+++ b/src/test/ui/consts/issue-78655.stderr
@@ -5,6 +5,11 @@ LL |     let x;
    |         - binding declared here but left uninitialized
 LL |     &x
    |     ^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
 
 error: could not evaluate constant pattern
   --> $DIR/issue-78655.rs:7:9
diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr
index 48fa2bfa975..e8d98477d32 100644
--- a/src/test/ui/drop/repeat-drop-2.stderr
+++ b/src/test/ui/drop/repeat-drop-2.stderr
@@ -24,6 +24,11 @@ LL |     let x: u8;
    |         - binding declared here but left uninitialized
 LL |     let _ = [x; 0];
    |              ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: u8 = 0;
+   |               +++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/loops/loop-proper-liveness.stderr b/src/test/ui/loops/loop-proper-liveness.stderr
index 14e86aee059..f9d94b6810c 100644
--- a/src/test/ui/loops/loop-proper-liveness.stderr
+++ b/src/test/ui/loops/loop-proper-liveness.stderr
@@ -8,6 +8,10 @@ LL |     println!("{:?}", x);
    |                      ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
index d8154f8d2cb..49f24ed39b4 100644
--- a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
+++ b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
@@ -24,6 +24,11 @@ LL |     let a: [String; 1];
 LL |
 LL |     a[0] = String::new();
    |     ^^^^ `a` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let a: [String; 1] = todo!();
+   |                        +++++++++
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
index c7373b5be9d..974994223a3 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -47,6 +47,11 @@ LL |         let value: NonCopy;
    |             ----- binding declared here but left uninitialized
 LL |         let _used = value;
    |                     ^^^^^ `value` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let value: NonCopy = todo!();
+   |                            +++++++++
 
 error[E0381]: used binding `value` isn't initialized
   --> $DIR/issue-72649-uninit-in-loop.rs:69:21
@@ -56,6 +61,11 @@ LL |     let mut value: NonCopy;
 LL |     loop {
 LL |         let _used = value;
    |                     ^^^^^ `value` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut value: NonCopy = todo!();
+   |                            +++++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/moves/move-into-dead-array-1.stderr b/src/test/ui/moves/move-into-dead-array-1.stderr
index 344a6bbf0c9..6db0f0bcbff 100644
--- a/src/test/ui/moves/move-into-dead-array-1.stderr
+++ b/src/test/ui/moves/move-into-dead-array-1.stderr
@@ -5,6 +5,11 @@ LL |     let mut a: [D; 4];
    |         ----- binding declared here but left uninitialized
 LL |     a[i] = d();
    |     ^^^^ `a` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut a: [D; 4] = todo!();
+   |                       +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-of-addr-of-mut.stderr b/src/test/ui/moves/move-of-addr-of-mut.stderr
index e75f2b1c089..ddebaa0129a 100644
--- a/src/test/ui/moves/move-of-addr-of-mut.stderr
+++ b/src/test/ui/moves/move-of-addr-of-mut.stderr
@@ -7,6 +7,10 @@ LL |     std::ptr::addr_of_mut!(x);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let mut x: S = todo!();
+   |                  +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index 250aa482e5c..2d48a914218 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -9,6 +9,11 @@ LL |         _ if { x = 2; true } => 1,
 LL |         _ if {
 LL |             x;
    |             ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/match-cfg-fake-edges.rs:35:13
diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr
index 664f36f695c..32666529f3f 100644
--- a/src/test/ui/nll/match-on-borrowed.stderr
+++ b/src/test/ui/nll/match-on-borrowed.stderr
@@ -40,6 +40,11 @@ LL |     let n: Never;
    |         - binding declared here but left uninitialized
 LL |     match n {}
    |           ^ `n` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let n: Never = todo!();
+   |                  +++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
index 95c209f47c9..0dfd22a30ac 100644
--- a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
+++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
@@ -6,6 +6,11 @@ LL |     let y: &mut u32;
 ...
 LL |     *y = 2;
    |     ^^^^^^ `y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let y: &mut u32 = todo!();
+   |                     +++++++++
 
 error: aborting due to previous error