No uninitalized report in a pre-returned match arm

This commit is contained in:
Lin Yihai 2024-06-11 17:31:06 +08:00
parent b5b13568fb
commit 5d8f40a63a
3 changed files with 54 additions and 4 deletions

View File

@ -557,8 +557,8 @@ fn report_use_of_uninitialized(
// for the branching codepaths that aren't covered, to point at them. // for the branching codepaths that aren't covered, to point at them.
let map = self.infcx.tcx.hir(); let map = self.infcx.tcx.hir();
let body = map.body_owned_by(self.mir_def_id()); let body = map.body_owned_by(self.mir_def_id());
let mut visitor =
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] }; ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
visitor.visit_body(&body); visitor.visit_body(&body);
let mut show_assign_sugg = false; let mut show_assign_sugg = false;
@ -4372,13 +4372,14 @@ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
/// Given a set of spans representing statements initializing the relevant binding, visit all the /// Given a set of spans representing statements initializing the relevant binding, visit all the
/// function expressions looking for branching code paths that *do not* initialize the binding. /// function expressions looking for branching code paths that *do not* initialize the binding.
struct ConditionVisitor<'b> { struct ConditionVisitor<'b, 'tcx> {
tcx: TyCtxt<'tcx>,
spans: &'b [Span], spans: &'b [Span],
name: &'b str, name: &'b str,
errors: Vec<(Span, String)>, errors: Vec<(Span, String)>,
} }
impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
match ex.kind { match ex.kind {
hir::ExprKind::If(cond, body, None) => { hir::ExprKind::If(cond, body, None) => {
@ -4464,6 +4465,12 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
), ),
)); ));
} else if let Some(guard) = &arm.guard { } else if let Some(guard) = &arm.guard {
if matches!(
self.tcx.hir_node(arm.body.hir_id),
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
) {
continue;
}
self.errors.push(( self.errors.push((
arm.pat.span.to(guard.span), arm.pat.span.to(guard.span),
format!( format!(
@ -4473,6 +4480,12 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
), ),
)); ));
} else { } else {
if matches!(
self.tcx.hir_node(arm.body.hir_id),
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
) {
continue;
}
self.errors.push(( self.errors.push((
arm.pat.span, arm.pat.span,
format!( format!(

View File

@ -0,0 +1,22 @@
enum E {
A,
B,
C,
}
fn foo(e: E) {
let bar;
match e {
E::A if true => return,
E::A => return,
E::B => {}
E::C => {
bar = 5;
}
}
let _baz = bar; //~ ERROR E0381
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0381]: used binding `bar` is possibly-uninitialized
--> $DIR/uninitalized-in-match-arm-issue-126133.rs:19:16
|
LL | let bar;
| --- binding declared here but left uninitialized
...
LL | E::B => {}
| ---- if this pattern is matched, `bar` is not initialized
...
LL | let _baz = bar;
| ^^^ `bar` used here but it is possibly-uninitialized
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0381`.