@@ -21,6 +21,7 @@ use rustc_middle::ty::{
21
21
self , subst:: Subst , suggest_constraining_type_params, EarlyBinder , PredicateKind , Ty ,
22
22
} ;
23
23
use rustc_mir_dataflow:: move_paths:: { InitKind , MoveOutIndex , MovePathIndex } ;
24
+ use rustc_span:: hygiene:: DesugaringKind ;
24
25
use rustc_span:: symbol:: sym;
25
26
use rustc_span:: { BytePos , Span } ;
26
27
use rustc_trait_selection:: infer:: InferCtxtExt ;
@@ -331,7 +332,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
331
332
spans. push ( span) ;
332
333
}
333
334
334
- let ( item_msg , name, desc) =
335
+ let ( binding , name, desc) =
335
336
match self . describe_place_with_options ( used_place, IncludingDowncast ( true ) ) {
336
337
Some ( name) => ( format ! ( "`{name}`" ) , format ! ( "`{name}`" ) , format ! ( "`{name}` " ) ) ,
337
338
None => ( "value" . to_string ( ) , "the variable" . to_string ( ) , String :: new ( ) ) ,
@@ -351,20 +352,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
351
352
} else {
352
353
"initialized in all conditions"
353
354
} ;
354
- let mut err = struct_span_err ! ( self , span, E0381 , "binding {desc}isn't {initialized}" ) ;
355
+ let used = desired_action. as_general_verb_in_past_tense ( ) ;
356
+ let mut err =
357
+ struct_span_err ! ( self , span, E0381 , "{used} binding {desc}isn't {initialized}" ) ;
355
358
use_spans. var_span_label_path_only (
356
359
& mut err,
357
360
format ! ( "{} occurs due to use{}" , desired_action. as_noun( ) , use_spans. describe( ) ) ,
358
361
) ;
359
362
360
363
if let InitializationRequiringAction :: PartialAssignment = desired_action {
361
364
err. help (
362
- "partial initialization isn't supported, fully initialize the binding with \
363
- a default value and mutate, or use `std::mem::MaybeUninit`",
365
+ "partial initialization isn't supported, fully initialize the binding with a \
366
+ default value and mutate it , or use `std::mem::MaybeUninit`",
364
367
) ;
365
368
}
366
- let verb = desired_action. as_verb_in_past_tense ( ) ;
367
- err. span_label ( span, format ! ( "{item_msg} {verb} here but it isn't {initialized}" , ) ) ;
369
+ err. span_label ( span, format ! ( "{binding} {used} here but it isn't {initialized}" ) ) ;
368
370
369
371
// We use the statements were the binding was initialized, and inspect the HIR to look
370
372
// for the branching codepaths that aren't covered, to point at them.
@@ -400,7 +402,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
400
402
err. span_label ( sp, & label) ;
401
403
}
402
404
}
403
- err. span_label ( decl_span, "variable declared here" ) ;
405
+ err. span_label ( decl_span, "binding declared here but left uninitialized " ) ;
404
406
err
405
407
}
406
408
@@ -2559,10 +2561,10 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
2559
2561
v. visit_expr ( body) ;
2560
2562
if v. 1 {
2561
2563
self . errors . push ( (
2562
- cond. span ,
2564
+ ex . span . to ( cond. span ) ,
2563
2565
format ! (
2564
- "this `if` expression might be missing an `else` arm where {} is \
2565
- initialized ",
2566
+ "this `if` expression might be missing an `else` arm that initializes \
2567
+ {} ",
2566
2568
self . name,
2567
2569
) ,
2568
2570
) ) ;
@@ -2578,10 +2580,24 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
2578
2580
match ( a. 1 , b. 1 ) {
2579
2581
( true , true ) | ( false , false ) => { }
2580
2582
( true , false ) => {
2581
- self . errors . push ( (
2582
- cond. span ,
2583
- format ! ( "{} is uninitialized if this condition isn't met" , self . name, ) ,
2584
- ) ) ;
2583
+ if other. span . is_desugaring ( DesugaringKind :: WhileLoop ) {
2584
+ self . errors . push ( (
2585
+ cond. span ,
2586
+ format ! (
2587
+ "{} is uninitialized if this condition isn't met and the \
2588
+ `while` loop runs 0 times",
2589
+ self . name
2590
+ ) ,
2591
+ ) ) ;
2592
+ } else {
2593
+ self . errors . push ( (
2594
+ body. span . shrink_to_hi ( ) . until ( other. span ) ,
2595
+ format ! (
2596
+ "{} is uninitialized if this `else` arm is executed" ,
2597
+ self . name
2598
+ ) ,
2599
+ ) ) ;
2600
+ }
2585
2601
}
2586
2602
( false , true ) => {
2587
2603
self . errors . push ( (
@@ -2591,7 +2607,7 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
2591
2607
}
2592
2608
}
2593
2609
}
2594
- hir:: ExprKind :: Match ( _ , arms, _ ) => {
2610
+ hir:: ExprKind :: Match ( e , arms, loop_desugar ) => {
2595
2611
// If the binding is initialized in one of the match arms, then the other match
2596
2612
// arms might be missing an initialization.
2597
2613
let results: Vec < bool > = arms
@@ -2605,22 +2621,40 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
2605
2621
if results. iter ( ) . any ( |x| * x) && !results. iter ( ) . all ( |x| * x) {
2606
2622
for ( arm, seen) in arms. iter ( ) . zip ( results) {
2607
2623
if !seen {
2608
- self . errors . push ( (
2609
- arm. pat . span ,
2610
- format ! (
2611
- "{} is uninitialized if this pattern is matched" ,
2612
- self . name
2613
- ) ,
2614
- ) ) ;
2624
+ if loop_desugar == hir:: MatchSource :: ForLoopDesugar {
2625
+ self . errors . push ( (
2626
+ e. span ,
2627
+ format ! (
2628
+ "{} is uninitialized if the `for` loop runs 0 times" ,
2629
+ self . name
2630
+ ) ,
2631
+ ) ) ;
2632
+ } else if let Some ( guard) = & arm. guard {
2633
+ self . errors . push ( (
2634
+ arm. pat . span . to ( guard. body ( ) . span ) ,
2635
+ format ! (
2636
+ "{} is uninitialized if this pattern and condition are \
2637
+ matched",
2638
+ self . name
2639
+ ) ,
2640
+ ) ) ;
2641
+ } else {
2642
+ self . errors . push ( (
2643
+ arm. pat . span ,
2644
+ format ! (
2645
+ "{} is uninitialized if this pattern is matched" ,
2646
+ self . name
2647
+ ) ,
2648
+ ) ) ;
2649
+ }
2615
2650
}
2616
2651
}
2617
2652
}
2618
2653
}
2619
2654
// FIXME: should we also account for binops, particularly `&&` and `||`? `try` should
2620
2655
// also be accounted for. For now it is fine, as if we don't find *any* relevant
2621
2656
// branching code paths, we point at the places where the binding *is* initialized for
2622
- // *some* context. We should also specialize the output for `while` and `for` loops,
2623
- // but for now we can rely on their desugaring to provide appropriate output.
2657
+ // *some* context.
2624
2658
_ => { }
2625
2659
}
2626
2660
walk_expr ( self , ex) ;
0 commit comments