@@ -2633,7 +2633,29 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2633
2633
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & hir:: Expr < ' _ > ) {
2634
2634
/// Information about why a type cannot be initialized this way.
2635
2635
/// Contains an error message and optionally a span to point at.
2636
- type InitError = ( String , Option < Span > ) ;
2636
+ struct InitError {
2637
+ msg : String ,
2638
+ span : Option < Span > ,
2639
+ generic : bool ,
2640
+ }
2641
+
2642
+ impl InitError {
2643
+ fn new ( msg : impl Into < String > ) -> Self {
2644
+ Self { msg : msg. into ( ) , span : None , generic : false }
2645
+ }
2646
+
2647
+ fn with_span ( msg : impl Into < String > , span : Span ) -> Self {
2648
+ Self { msg : msg. into ( ) , span : Some ( span) , generic : false }
2649
+ }
2650
+
2651
+ fn generic ( ) -> Self {
2652
+ Self {
2653
+ msg : "type might not be allowed to be left uninitialized" . to_string ( ) ,
2654
+ span : None ,
2655
+ generic : true ,
2656
+ }
2657
+ }
2658
+ }
2637
2659
2638
2660
/// Determine if this expression is a "dangerous initialization".
2639
2661
fn is_dangerous_init ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
@@ -2657,18 +2679,18 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2657
2679
use rustc_type_ir:: sty:: TyKind :: * ;
2658
2680
match ty. kind ( ) {
2659
2681
// Primitive types that don't like 0 as a value.
2660
- Ref ( ..) => Some ( ( "references must be non-null" . to_string ( ) , None ) ) ,
2661
- Adt ( ..) if ty. is_box ( ) => Some ( ( "`Box` must be non-null" . to_string ( ) , None ) ) ,
2662
- FnPtr ( ..) => Some ( ( "function pointers must be non-null" . to_string ( ) , None ) ) ,
2663
- Never => Some ( ( "the `!` type has no valid value" . to_string ( ) , None ) ) ,
2682
+ Ref ( ..) => Some ( InitError :: new ( "references must be non-null" ) ) ,
2683
+ Adt ( ..) if ty. is_box ( ) => Some ( InitError :: new ( "`Box` must be non-null" ) ) ,
2684
+ FnPtr ( ..) => Some ( InitError :: new ( "function pointers must be non-null" ) ) ,
2685
+ Never => Some ( InitError :: new ( "the `!` type has no valid value" ) ) ,
2664
2686
RawPtr ( tm) if matches ! ( tm. ty. kind( ) , Dynamic ( ..) ) =>
2665
2687
// raw ptr to dyn Trait
2666
2688
{
2667
- Some ( ( "the vtable of a wide raw pointer must be non-null" . to_string ( ) , None ) )
2689
+ Some ( InitError :: new ( "the vtable of a wide raw pointer must be non-null" ) )
2668
2690
}
2669
2691
// Primitive types with other constraints.
2670
- Bool => Some ( ( "booleans must be either `true` or `false`" . to_string ( ) , None ) ) ,
2671
- Char => Some ( ( "characters must be a valid Unicode codepoint" . to_string ( ) , None ) ) ,
2692
+ Bool => Some ( InitError :: new ( "booleans must be either `true` or `false`" ) ) ,
2693
+ Char => Some ( InitError :: new ( "characters must be a valid Unicode codepoint" ) ) ,
2672
2694
Adt ( adt_def, _) if adt_def. is_union ( ) => None ,
2673
2695
// Recurse and checks for some compound types.
2674
2696
Adt ( adt_def, substs) => {
@@ -2679,29 +2701,25 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2679
2701
// return `Bound::Excluded`. (And we have tests checking that we
2680
2702
// handle the attribute correctly.)
2681
2703
( Bound :: Included ( lo) , _) if lo > 0 => {
2682
- return Some ( ( format ! ( "`{}` must be non-null" , ty ) , None ) ) ;
2704
+ return Some ( InitError :: new ( format ! ( "`{ty }` must be non-null" ) ) ) ;
2683
2705
}
2684
2706
( Bound :: Included ( _) , _) | ( _, Bound :: Included ( _) ) => {
2685
- return Some ( (
2686
- format ! (
2687
- "`{}` must be initialized inside its custom valid range" ,
2688
- ty,
2689
- ) ,
2690
- None ,
2691
- ) ) ;
2707
+ return Some ( InitError :: new ( format ! (
2708
+ "`{ty}` must be initialized inside its custom valid range"
2709
+ ) ) ) ;
2692
2710
}
2693
2711
_ => { }
2694
2712
}
2695
2713
// Now, recurse.
2696
2714
match adt_def. variants ( ) . len ( ) {
2697
- 0 => Some ( ( "enums with no variants have no valid value" . to_string ( ) , None ) ) ,
2715
+ 0 => Some ( InitError :: new ( "enums with no variants have no valid value" ) ) ,
2698
2716
1 => {
2699
2717
// Struct, or enum with exactly one variant.
2700
2718
// Proceed recursively, check all fields.
2701
2719
let variant = & adt_def. variant ( VariantIdx :: from_u32 ( 0 ) ) ;
2702
2720
variant. fields . iter ( ) . find_map ( |field| {
2703
2721
ty_find_init_error ( cx, field. ty ( cx. tcx , substs) ) . map (
2704
- |( mut msg, span) | {
2722
+ |InitError { mut msg, span, generic } | {
2705
2723
if span. is_none ( ) {
2706
2724
// Point to this field, should be helpful for figuring
2707
2725
// out where the source of the error is.
@@ -2712,10 +2730,11 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2712
2730
adt_def. descr( )
2713
2731
)
2714
2732
. unwrap ( ) ;
2715
- ( msg, Some ( span) )
2733
+
2734
+ InitError { msg, span : Some ( span) , generic }
2716
2735
} else {
2717
2736
// Just forward.
2718
- ( msg, span)
2737
+ InitError { msg, span, generic }
2719
2738
}
2720
2739
} ,
2721
2740
)
@@ -2729,9 +2748,9 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2729
2748
//
2730
2749
// That's probably fine though.
2731
2750
let span = cx. tcx . def_span ( adt_def. did ( ) ) ;
2732
- Some ( (
2733
- "enums have to be initialized to a variant" . to_string ( ) ,
2734
- Some ( span) ,
2751
+ Some ( InitError :: with_span (
2752
+ "enums have to be initialized to a variant" ,
2753
+ span,
2735
2754
) )
2736
2755
}
2737
2756
}
@@ -2745,7 +2764,14 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2745
2764
// Array known to be zero sized, we can't warn.
2746
2765
Some ( 0 ) => None ,
2747
2766
2748
- Some ( _) | None => ty_find_init_error ( cx, * ty) ,
2767
+ // Array length known to be nonzero, warn.
2768
+ Some ( 1 ..) => ty_find_init_error ( cx, * ty) ,
2769
+
2770
+ // Array length unknown, use the "might not permit" wording.
2771
+ None => ty_find_init_error ( cx, * ty) . map ( |mut e| {
2772
+ e. generic = true ;
2773
+ e
2774
+ } ) ,
2749
2775
}
2750
2776
}
2751
2777
Int ( _) | Uint ( _) | Float ( _) | RawPtr ( _) => {
@@ -2754,7 +2780,7 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2754
2780
None
2755
2781
}
2756
2782
// Pessimistic fallback.
2757
- _ => Some ( ( "type might not be allowed to be left uninitialized" . to_string ( ) , None ) ) ,
2783
+ _ => Some ( InitError :: generic ( ) ) ,
2758
2784
}
2759
2785
}
2760
2786
@@ -2763,24 +2789,29 @@ impl<'tcx> LateLintPass<'tcx> for MemUninitialized {
2763
2789
// using zeroed or uninitialized memory.
2764
2790
// We are extremely conservative with what we warn about.
2765
2791
let conjured_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
2766
- if let Some ( ( msg, span) ) = with_no_trimmed_paths ! ( ty_find_init_error( cx, conjured_ty) ) {
2792
+ if let Some ( init_error) = with_no_trimmed_paths ! ( ty_find_init_error( cx, conjured_ty) ) {
2793
+ let main_msg = with_no_trimmed_paths ! ( if init_error. generic {
2794
+ format!(
2795
+ "the type `{conjured_ty}` is generic, and might not permit being left uninitialized"
2796
+ )
2797
+ } else {
2798
+ format!( "the type `{conjured_ty}` does not permit being left uninitialized" )
2799
+ } ) ;
2800
+
2767
2801
// FIXME(davidtwco): make translatable
2768
2802
cx. struct_span_lint ( MEM_UNINITIALIZED , expr. span , |lint| {
2769
- let mut err = with_no_trimmed_paths ! ( lint. build( & format!(
2770
- "the type `{}` does not definitely permit being left uninitialized" ,
2771
- conjured_ty,
2772
- ) ) ) ;
2803
+ let mut err = lint. build ( & main_msg) ;
2773
2804
2774
2805
err. span_label ( expr. span , "this code causes undefined behavior when executed" ) ;
2775
2806
err. span_label (
2776
2807
expr. span ,
2777
2808
"help: use `MaybeUninit<T>` instead, \
2778
2809
and only call `assume_init` after initialization is done",
2779
2810
) ;
2780
- if let Some ( span) = span {
2781
- err. span_note ( span, & msg) ;
2811
+ if let Some ( span) = init_error . span {
2812
+ err. span_note ( span, & init_error . msg ) ;
2782
2813
} else {
2783
- err. note ( & msg) ;
2814
+ err. note ( & init_error . msg ) ;
2784
2815
}
2785
2816
err. emit ( ) ;
2786
2817
} ) ;
0 commit comments