@@ -57,8 +57,6 @@ use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
57
57
58
58
use crate :: nonstandard_style:: { method_context, MethodLateContext } ;
59
59
60
- use std:: fmt:: Write ;
61
-
62
60
// hardwired lints from librustc_middle
63
61
pub use rustc_session:: lint:: builtin:: * ;
64
62
@@ -2408,8 +2406,34 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2408
2406
}
2409
2407
2410
2408
/// Information about why a type cannot be initialized this way.
2411
- /// Contains an error message and optionally a span to point at.
2412
- type InitError = ( String , Option < Span > ) ;
2409
+ struct InitError {
2410
+ message : String ,
2411
+ /// Spans from struct fields and similar can be obtained from just the type.
2412
+ span : Option < Span > ,
2413
+ /// Used to report a trace through adts.
2414
+ nested : Option < Box < InitError > > ,
2415
+ }
2416
+ impl InitError {
2417
+ fn spanned ( self , span : Span ) -> InitError {
2418
+ Self { span : Some ( span) , ..self }
2419
+ }
2420
+
2421
+ fn nested ( self , nested : InitError ) -> InitError {
2422
+ assert ! ( self . nested. is_none( ) ) ;
2423
+ Self { nested : Some ( Box :: new ( nested) ) , ..self }
2424
+ }
2425
+ }
2426
+
2427
+ impl < ' a > From < & ' a str > for InitError {
2428
+ fn from ( s : & ' a str ) -> Self {
2429
+ s. to_owned ( ) . into ( )
2430
+ }
2431
+ }
2432
+ impl From < String > for InitError {
2433
+ fn from ( message : String ) -> Self {
2434
+ Self { message, span : None , nested : None }
2435
+ }
2436
+ }
2413
2437
2414
2438
/// Test if this constant is all-0.
2415
2439
fn is_zero ( expr : & hir:: Expr < ' _ > ) -> bool {
@@ -2471,17 +2495,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2471
2495
init : InitKind ,
2472
2496
) -> Option < InitError > {
2473
2497
variant. fields . iter ( ) . find_map ( |field| {
2474
- ty_find_init_error ( cx, field. ty ( cx. tcx , substs) , init) . map ( |( mut msg, span) | {
2475
- if span. is_none ( ) {
2476
- // Point to this field, should be helpful for figuring
2477
- // out where the source of the error is.
2478
- let span = cx. tcx . def_span ( field. did ) ;
2479
- write ! ( & mut msg, " (in this {descr})" ) . unwrap ( ) ;
2480
- ( msg, Some ( span) )
2481
- } else {
2482
- // Just forward.
2483
- ( msg, span)
2484
- }
2498
+ ty_find_init_error ( cx, field. ty ( cx. tcx , substs) , init) . map ( |err| {
2499
+ InitError :: from ( format ! ( "in this {descr}" ) )
2500
+ . spanned ( cx. tcx . def_span ( field. did ) )
2501
+ . nested ( err)
2485
2502
} )
2486
2503
} )
2487
2504
}
@@ -2496,30 +2513,30 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2496
2513
use rustc_type_ir:: sty:: TyKind :: * ;
2497
2514
match ty. kind ( ) {
2498
2515
// Primitive types that don't like 0 as a value.
2499
- Ref ( ..) => Some ( ( "references must be non-null" . to_string ( ) , None ) ) ,
2500
- Adt ( ..) if ty. is_box ( ) => Some ( ( "`Box` must be non-null" . to_string ( ) , None ) ) ,
2501
- FnPtr ( ..) => Some ( ( "function pointers must be non-null" . to_string ( ) , None ) ) ,
2502
- Never => Some ( ( "the `!` type has no valid value" . to_string ( ) , None ) ) ,
2516
+ Ref ( ..) => Some ( "references must be non-null" . into ( ) ) ,
2517
+ Adt ( ..) if ty. is_box ( ) => Some ( "`Box` must be non-null" . into ( ) ) ,
2518
+ FnPtr ( ..) => Some ( "function pointers must be non-null" . into ( ) ) ,
2519
+ Never => Some ( "the `!` type has no valid value" . into ( ) ) ,
2503
2520
RawPtr ( tm) if matches ! ( tm. ty. kind( ) , Dynamic ( ..) ) =>
2504
2521
// raw ptr to dyn Trait
2505
2522
{
2506
- Some ( ( "the vtable of a wide raw pointer must be non-null" . to_string ( ) , None ) )
2523
+ Some ( "the vtable of a wide raw pointer must be non-null" . into ( ) )
2507
2524
}
2508
2525
// Primitive types with other constraints.
2509
2526
Bool if init == InitKind :: Uninit => {
2510
- Some ( ( "booleans must be either `true` or `false`" . to_string ( ) , None ) )
2527
+ Some ( "booleans must be either `true` or `false`" . into ( ) )
2511
2528
}
2512
2529
Char if init == InitKind :: Uninit => {
2513
- Some ( ( "characters must be a valid Unicode codepoint" . to_string ( ) , None ) )
2530
+ Some ( "characters must be a valid Unicode codepoint" . into ( ) )
2514
2531
}
2515
2532
Int ( _) | Uint ( _) if init == InitKind :: Uninit => {
2516
- Some ( ( "integers must not be uninitialized" . to_string ( ) , None ) )
2533
+ Some ( "integers must not be uninitialized" . into ( ) )
2517
2534
}
2518
2535
Float ( _) if init == InitKind :: Uninit => {
2519
- Some ( ( "floats must not be uninitialized" . to_string ( ) , None ) )
2536
+ Some ( "floats must not be uninitialized" . into ( ) )
2520
2537
}
2521
2538
RawPtr ( _) if init == InitKind :: Uninit => {
2522
- Some ( ( "raw pointers must not be uninitialized" . to_string ( ) , None ) )
2539
+ Some ( "raw pointers must not be uninitialized" . into ( ) )
2523
2540
}
2524
2541
// Recurse and checks for some compound types. (but not unions)
2525
2542
Adt ( adt_def, substs) if !adt_def. is_union ( ) => {
@@ -2531,21 +2548,21 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2531
2548
// handle the attribute correctly.)
2532
2549
// We don't add a span since users cannot declare such types anyway.
2533
2550
( Bound :: Included ( lo) , Bound :: Included ( hi) ) if 0 < lo && lo < hi => {
2534
- return Some ( ( format ! ( "`{}` must be non-null" , ty) , None ) ) ;
2551
+ return Some ( format ! ( "`{}` must be non-null" , ty) . into ( ) ) ;
2535
2552
}
2536
2553
( Bound :: Included ( lo) , Bound :: Unbounded ) if 0 < lo => {
2537
- return Some ( ( format ! ( "`{}` must be non-null" , ty) , None ) ) ;
2554
+ return Some ( format ! ( "`{}` must be non-null" , ty) . into ( ) ) ;
2538
2555
}
2539
2556
( Bound :: Included ( _) , _) | ( _, Bound :: Included ( _) )
2540
2557
if init == InitKind :: Uninit =>
2541
2558
{
2542
- return Some ( (
2559
+ return Some (
2543
2560
format ! (
2544
2561
"`{}` must be initialized inside its custom valid range" ,
2545
2562
ty,
2546
- ) ,
2547
- None ,
2548
- ) ) ;
2563
+ )
2564
+ . into ( ) ,
2565
+ ) ;
2549
2566
}
2550
2567
_ => { }
2551
2568
}
@@ -2576,7 +2593,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2576
2593
Some ( ( variant, definitely_inhabited) )
2577
2594
} ) ;
2578
2595
let Some ( first_variant) = potential_variants. next ( ) else {
2579
- return Some ( ( "enums with no inhabited variants have no valid value" . to_string ( ) , Some ( span) ) ) ;
2596
+ return Some ( InitError :: from ( "enums with no inhabited variants have no valid value" ) . spanned ( span) ) ;
2580
2597
} ;
2581
2598
// So we have at least one potentially inhabited variant. Might we have two?
2582
2599
let Some ( second_variant) = potential_variants. next ( ) else {
@@ -2600,10 +2617,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2600
2617
. filter ( |( _variant, definitely_inhabited) | * definitely_inhabited)
2601
2618
. count ( ) ;
2602
2619
if definitely_inhabited > 1 {
2603
- return Some ( (
2604
- "enums with multiple inhabited variants have to be initialized to a variant" . to_string ( ) ,
2605
- Some ( span) ,
2606
- ) ) ;
2620
+ return Some ( InitError :: from (
2621
+ "enums with multiple inhabited variants have to be initialized to a variant" ,
2622
+ ) . spanned ( span) ) ;
2607
2623
}
2608
2624
}
2609
2625
// We couldn't find anything wrong here.
@@ -2632,8 +2648,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2632
2648
// using zeroed or uninitialized memory.
2633
2649
// We are extremely conservative with what we warn about.
2634
2650
let conjured_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
2635
- if let Some ( ( msg, span) ) =
2636
- with_no_trimmed_paths ! ( ty_find_init_error( cx, conjured_ty, init) )
2651
+ if let Some ( mut err) = with_no_trimmed_paths ! ( ty_find_init_error( cx, conjured_ty, init) )
2637
2652
{
2638
2653
// FIXME(davidtwco): make translatable
2639
2654
cx. struct_span_lint (
@@ -2659,10 +2674,17 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2659
2674
"help: use `MaybeUninit<T>` instead, \
2660
2675
and only call `assume_init` after initialization is done",
2661
2676
) ;
2662
- if let Some ( span) = span {
2663
- lint. span_note ( span, & msg) ;
2664
- } else {
2665
- lint. note ( & msg) ;
2677
+ loop {
2678
+ if let Some ( span) = err. span {
2679
+ lint. span_note ( span, & err. message ) ;
2680
+ } else {
2681
+ lint. note ( & err. message ) ;
2682
+ }
2683
+ if let Some ( e) = err. nested {
2684
+ err = * e;
2685
+ } else {
2686
+ break ;
2687
+ }
2666
2688
}
2667
2689
lint
2668
2690
} ,
0 commit comments