@@ -57,8 +57,6 @@ use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
5757
5858use crate :: nonstandard_style:: { method_context, MethodLateContext } ;
5959
60- use std:: fmt:: Write ;
61-
6260// hardwired lints from librustc_middle
6361pub use rustc_session:: lint:: builtin:: * ;
6462
@@ -2408,8 +2406,34 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24082406 }
24092407
24102408 /// 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+ }
24132437
24142438 /// Test if this constant is all-0.
24152439 fn is_zero ( expr : & hir:: Expr < ' _ > ) -> bool {
@@ -2471,17 +2495,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24712495 init : InitKind ,
24722496 ) -> Option < InitError > {
24732497 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)
24852502 } )
24862503 } )
24872504 }
@@ -2496,30 +2513,30 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24962513 use rustc_type_ir:: sty:: TyKind :: * ;
24972514 match ty. kind ( ) {
24982515 // 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 ( ) ) ,
25032520 RawPtr ( tm) if matches ! ( tm. ty. kind( ) , Dynamic ( ..) ) =>
25042521 // raw ptr to dyn Trait
25052522 {
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 ( ) )
25072524 }
25082525 // Primitive types with other constraints.
25092526 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 ( ) )
25112528 }
25122529 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 ( ) )
25142531 }
25152532 Int ( _) | Uint ( _) if init == InitKind :: Uninit => {
2516- Some ( ( "integers must not be uninitialized" . to_string ( ) , None ) )
2533+ Some ( "integers must not be uninitialized" . into ( ) )
25172534 }
25182535 Float ( _) if init == InitKind :: Uninit => {
2519- Some ( ( "floats must not be uninitialized" . to_string ( ) , None ) )
2536+ Some ( "floats must not be uninitialized" . into ( ) )
25202537 }
25212538 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 ( ) )
25232540 }
25242541 // Recurse and checks for some compound types. (but not unions)
25252542 Adt ( adt_def, substs) if !adt_def. is_union ( ) => {
@@ -2531,21 +2548,21 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
25312548 // handle the attribute correctly.)
25322549 // We don't add a span since users cannot declare such types anyway.
25332550 ( 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 ( ) ) ;
25352552 }
25362553 ( 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 ( ) ) ;
25382555 }
25392556 ( Bound :: Included ( _) , _) | ( _, Bound :: Included ( _) )
25402557 if init == InitKind :: Uninit =>
25412558 {
2542- return Some ( (
2559+ return Some (
25432560 format ! (
25442561 "`{}` must be initialized inside its custom valid range" ,
25452562 ty,
2546- ) ,
2547- None ,
2548- ) ) ;
2563+ )
2564+ . into ( ) ,
2565+ ) ;
25492566 }
25502567 _ => { }
25512568 }
@@ -2576,7 +2593,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
25762593 Some ( ( variant, definitely_inhabited) )
25772594 } ) ;
25782595 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) ) ;
25802597 } ;
25812598 // So we have at least one potentially inhabited variant. Might we have two?
25822599 let Some ( second_variant) = potential_variants. next ( ) else {
@@ -2600,10 +2617,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
26002617 . filter ( |( _variant, definitely_inhabited) | * definitely_inhabited)
26012618 . count ( ) ;
26022619 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) ) ;
26072623 }
26082624 }
26092625 // We couldn't find anything wrong here.
@@ -2632,8 +2648,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
26322648 // using zeroed or uninitialized memory.
26332649 // We are extremely conservative with what we warn about.
26342650 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) )
26372652 {
26382653 // FIXME(davidtwco): make translatable
26392654 cx. struct_span_lint (
@@ -2659,10 +2674,17 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
26592674 "help: use `MaybeUninit<T>` instead, \
26602675 and only call `assume_init` after initialization is done",
26612676 ) ;
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+ }
26662688 }
26672689 lint
26682690 } ,
0 commit comments