@@ -2366,7 +2366,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2366
2366
#[ derive( Debug , Copy , Clone , PartialEq ) ]
2367
2367
enum InitKind {
2368
2368
Zeroed ,
2369
- Uninit ,
2369
+ Uninit { is_mem_uninit : bool } ,
2370
+ }
2371
+
2372
+ impl InitKind {
2373
+ fn is_uninit ( self ) -> bool {
2374
+ matches ! ( self , InitKind :: Uninit { .. } )
2375
+ }
2370
2376
}
2371
2377
2372
2378
/// Information about why a type cannot be initialized this way.
@@ -2398,7 +2404,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2398
2404
let def_id = cx. qpath_res ( qpath, path_expr. hir_id ) . opt_def_id ( ) ?;
2399
2405
match cx. tcx . get_diagnostic_name ( def_id) {
2400
2406
Some ( sym:: mem_zeroed) => return Some ( InitKind :: Zeroed ) ,
2401
- Some ( sym:: mem_uninitialized) => return Some ( InitKind :: Uninit ) ,
2407
+ Some ( sym:: mem_uninitialized) => {
2408
+ return Some ( InitKind :: Uninit { is_mem_uninit : true } ) ;
2409
+ }
2402
2410
Some ( sym:: transmute) if is_zero ( & args[ 0 ] ) => return Some ( InitKind :: Zeroed ) ,
2403
2411
_ => { }
2404
2412
}
@@ -2414,7 +2422,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2414
2422
let def_id = cx. qpath_res ( qpath, path_expr. hir_id ) . opt_def_id ( ) ?;
2415
2423
match cx. tcx . get_diagnostic_name ( def_id) {
2416
2424
Some ( sym:: maybe_uninit_zeroed) => return Some ( InitKind :: Zeroed ) ,
2417
- Some ( sym:: maybe_uninit_uninit) => return Some ( InitKind :: Uninit ) ,
2425
+ Some ( sym:: maybe_uninit_uninit) => {
2426
+ return Some ( InitKind :: Uninit { is_mem_uninit : false } ) ;
2427
+ }
2418
2428
_ => { }
2419
2429
}
2420
2430
}
@@ -2453,19 +2463,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2453
2463
Some ( ( "the vtable of a wide raw pointer must be non-null" . to_string ( ) , None ) )
2454
2464
}
2455
2465
// Primitive types with other constraints.
2456
- Bool if init == InitKind :: Uninit => {
2466
+ Bool if init. is_uninit ( ) => {
2457
2467
Some ( ( "booleans must be either `true` or `false`" . to_string ( ) , None ) )
2458
2468
}
2459
- Char if init == InitKind :: Uninit => {
2469
+ Char if init. is_uninit ( ) => {
2460
2470
Some ( ( "characters must be a valid Unicode codepoint" . to_string ( ) , None ) )
2461
2471
}
2462
- Int ( _) | Uint ( _) if init == InitKind :: Uninit => {
2472
+ Int ( _) | Uint ( _) if init. is_uninit ( ) => {
2463
2473
Some ( ( "integers must not be uninitialized" . to_string ( ) , None ) )
2464
2474
}
2465
- Float ( _) if init == InitKind :: Uninit => {
2475
+ Float ( _) if init. is_uninit ( ) => {
2466
2476
Some ( ( "floats must not be uninitialized" . to_string ( ) , None ) )
2467
2477
}
2468
- RawPtr ( _) if init == InitKind :: Uninit => {
2478
+ RawPtr ( _) if init. is_uninit ( ) => {
2469
2479
Some ( ( "raw pointers must not be uninitialized" . to_string ( ) , None ) )
2470
2480
}
2471
2481
// Recurse and checks for some compound types.
@@ -2479,9 +2489,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2479
2489
( Bound :: Included ( lo) , _) if lo > 0 => {
2480
2490
return Some ( ( format ! ( "`{}` must be non-null" , ty) , None ) ) ;
2481
2491
}
2482
- ( Bound :: Included ( _) , _) | ( _, Bound :: Included ( _) )
2483
- if init == InitKind :: Uninit =>
2484
- {
2492
+ ( Bound :: Included ( _) , _) | ( _, Bound :: Included ( _) ) if init. is_uninit ( ) => {
2485
2493
return Some ( (
2486
2494
format ! (
2487
2495
"`{}` must be initialized inside its custom valid range" ,
@@ -2523,7 +2531,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2523
2531
}
2524
2532
// Multi-variant enum.
2525
2533
_ => {
2526
- if init == InitKind :: Uninit && is_multi_variant ( * adt_def) {
2534
+ if init. is_uninit ( ) && is_multi_variant ( * adt_def) {
2527
2535
let span = cx. tcx . def_span ( adt_def. did ( ) ) ;
2528
2536
Some ( (
2529
2537
"enums have to be initialized to a variant" . to_string ( ) ,
@@ -2560,6 +2568,16 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2560
2568
// using zeroed or uninitialized memory.
2561
2569
// We are extremely conservative with what we warn about.
2562
2570
let conjured_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
2571
+
2572
+ if init == ( InitKind :: Uninit { is_mem_uninit : true } ) {
2573
+ // We don't want to warn here for things that mem_uninitialized will warn about
2574
+ if with_no_trimmed_paths ! (
2575
+ crate :: mem_uninitialized:: ty_find_init_error( cx, conjured_ty) . is_some( )
2576
+ ) {
2577
+ return ;
2578
+ }
2579
+ }
2580
+
2563
2581
if let Some ( ( msg, span) ) =
2564
2582
with_no_trimmed_paths ! ( ty_find_init_error( cx, conjured_ty, init) )
2565
2583
{
@@ -2570,7 +2588,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2570
2588
conjured_ty,
2571
2589
match init {
2572
2590
InitKind :: Zeroed => "zero-initialization" ,
2573
- InitKind :: Uninit => "being left uninitialized" ,
2591
+ InitKind :: Uninit { .. } => "being left uninitialized" ,
2574
2592
} ,
2575
2593
) ) ;
2576
2594
err. span_label ( expr. span , "this code causes undefined behavior when executed" ) ;
@@ -2591,235 +2609,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2591
2609
}
2592
2610
}
2593
2611
2594
- declare_lint ! {
2595
- /// The `mem_uninitialized` lint detects all uses of `std::mem::uninitialized` that are not
2596
- /// known to be safe.
2597
- ///
2598
- /// This function is extremely dangerous, and nearly all uses of it cause immediate Undefined
2599
- /// Behavior.
2600
- ///
2601
- /// ### Example
2602
- ///
2603
- /// ```rust,compile_fail
2604
- /// #![deny(mem_uninitialized)]
2605
- /// fn main() {
2606
- /// let x: [char; 16] = unsafe { std::mem::uninitialized() };
2607
- /// }
2608
- /// ```
2609
- ///
2610
- /// {{produces}}
2611
- ///
2612
- /// ### Explanation
2613
- ///
2614
- /// Creating an invalid value is undefined behavior, and nearly all types are invalid when left
2615
- /// uninitialized.
2616
- ///
2617
- /// To avoid churn, however, this will not lint for types made up entirely of integers, floats,
2618
- /// or raw pointers. This is not saying that leaving these types uninitialized is okay,
2619
- /// however.
2620
- pub MEM_UNINITIALIZED ,
2621
- Warn ,
2622
- "use of mem::uninitialized" ,
2623
- @future_incompatible = FutureIncompatibleInfo {
2624
- reference: "FIXME: fill this in" ,
2625
- reason: FutureIncompatibilityReason :: FutureReleaseErrorReportNow ,
2626
- explain_reason: false ,
2627
- } ;
2628
- }
2629
-
2630
- declare_lint_pass ! ( MemUninitialized => [ MEM_UNINITIALIZED ] ) ;
2631
-
2632
- impl < ' tcx > LateLintPass < ' tcx > for MemUninitialized {
2633
- fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & hir:: Expr < ' _ > ) {
2634
- /// Information about why a type cannot be initialized this way.
2635
- /// Contains an error message and optionally a span to point at.
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
- }
2659
-
2660
- /// Determine if this expression is a "dangerous initialization".
2661
- fn is_dangerous_init ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
2662
- if let hir:: ExprKind :: Call ( ref path_expr, _) = expr. kind {
2663
- // Find calls to `mem::{uninitialized,zeroed}` methods.
2664
- if let hir:: ExprKind :: Path ( ref qpath) = path_expr. kind {
2665
- if let Some ( def_id) = cx. qpath_res ( qpath, path_expr. hir_id ) . opt_def_id ( ) {
2666
- if cx. tcx . is_diagnostic_item ( sym:: mem_uninitialized, def_id) {
2667
- return true ;
2668
- }
2669
- }
2670
- }
2671
- }
2672
-
2673
- false
2674
- }
2675
-
2676
- /// Return `None` only if we are sure this type does
2677
- /// allow being left uninitialized.
2678
- fn ty_find_init_error < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Option < InitError > {
2679
- use rustc_type_ir:: sty:: TyKind :: * ;
2680
- match ty. kind ( ) {
2681
- // Primitive types that don't like 0 as a value.
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" ) ) ,
2686
- RawPtr ( tm) if matches ! ( tm. ty. kind( ) , Dynamic ( ..) ) =>
2687
- // raw ptr to dyn Trait
2688
- {
2689
- Some ( InitError :: new ( "the vtable of a wide raw pointer must be non-null" ) )
2690
- }
2691
- // Primitive types with other constraints.
2692
- Bool => Some ( InitError :: new ( "booleans must be either `true` or `false`" ) ) ,
2693
- Char => Some ( InitError :: new ( "characters must be a valid Unicode codepoint" ) ) ,
2694
- Adt ( adt_def, _) if adt_def. is_union ( ) => None ,
2695
- // Recurse and checks for some compound types.
2696
- Adt ( adt_def, substs) => {
2697
- // First check if this ADT has a layout attribute (like `NonNull` and friends).
2698
- use std:: ops:: Bound ;
2699
- match cx. tcx . layout_scalar_valid_range ( adt_def. did ( ) ) {
2700
- // We exploit here that `layout_scalar_valid_range` will never
2701
- // return `Bound::Excluded`. (And we have tests checking that we
2702
- // handle the attribute correctly.)
2703
- ( Bound :: Included ( lo) , _) if lo > 0 => {
2704
- return Some ( InitError :: new ( format ! ( "`{ty}` must be non-null" ) ) ) ;
2705
- }
2706
- ( Bound :: Included ( _) , _) | ( _, Bound :: Included ( _) ) => {
2707
- return Some ( InitError :: new ( format ! (
2708
- "`{ty}` must be initialized inside its custom valid range"
2709
- ) ) ) ;
2710
- }
2711
- _ => { }
2712
- }
2713
- // Now, recurse.
2714
- match adt_def. variants ( ) . len ( ) {
2715
- 0 => Some ( InitError :: new ( "enums with no variants have no valid value" ) ) ,
2716
- 1 => {
2717
- // Struct, or enum with exactly one variant.
2718
- // Proceed recursively, check all fields.
2719
- let variant = & adt_def. variant ( VariantIdx :: from_u32 ( 0 ) ) ;
2720
- variant. fields . iter ( ) . find_map ( |field| {
2721
- ty_find_init_error ( cx, field. ty ( cx. tcx , substs) ) . map (
2722
- |InitError { mut msg, span, generic } | {
2723
- if span. is_none ( ) {
2724
- // Point to this field, should be helpful for figuring
2725
- // out where the source of the error is.
2726
- let span = cx. tcx . def_span ( field. did ) ;
2727
- write ! (
2728
- & mut msg,
2729
- " (in this {} field)" ,
2730
- adt_def. descr( )
2731
- )
2732
- . unwrap ( ) ;
2733
-
2734
- InitError { msg, span : Some ( span) , generic }
2735
- } else {
2736
- // Just forward.
2737
- InitError { msg, span, generic }
2738
- }
2739
- } ,
2740
- )
2741
- } )
2742
- }
2743
- // Multi-variant enum.
2744
- _ => {
2745
- // This will warn on something like Result<MaybeUninit<u32>, !> which
2746
- // is not UB under the current enum layout, even ignoring the 0x01
2747
- // filling.
2748
- //
2749
- // That's probably fine though.
2750
- let span = cx. tcx . def_span ( adt_def. did ( ) ) ;
2751
- Some ( InitError :: with_span (
2752
- "enums have to be initialized to a variant" ,
2753
- span,
2754
- ) )
2755
- }
2756
- }
2757
- }
2758
- Tuple ( ..) => {
2759
- // Proceed recursively, check all fields.
2760
- ty. tuple_fields ( ) . iter ( ) . find_map ( |field| ty_find_init_error ( cx, field) )
2761
- }
2762
- Array ( ty, len) => {
2763
- match len. try_eval_usize ( cx. tcx , cx. param_env ) {
2764
- // Array known to be zero sized, we can't warn.
2765
- Some ( 0 ) => None ,
2766
-
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
- } ) ,
2775
- }
2776
- }
2777
- Int ( _) | Uint ( _) | Float ( _) | RawPtr ( _) => {
2778
- // These are Plain Old Data types that people expect to work if they leave them
2779
- // uninitialized.
2780
- None
2781
- }
2782
- // Pessimistic fallback.
2783
- _ => Some ( InitError :: generic ( ) ) ,
2784
- }
2785
- }
2786
-
2787
- if is_dangerous_init ( cx, expr) {
2788
- // This conjures an instance of a type out of nothing,
2789
- // using zeroed or uninitialized memory.
2790
- // We are extremely conservative with what we warn about.
2791
- let conjured_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
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
-
2801
- // FIXME(davidtwco): make translatable
2802
- cx. struct_span_lint ( MEM_UNINITIALIZED , expr. span , |lint| {
2803
- let mut err = lint. build ( & main_msg) ;
2804
-
2805
- err. span_label ( expr. span , "this code causes undefined behavior when executed" ) ;
2806
- err. span_label (
2807
- expr. span ,
2808
- "help: use `MaybeUninit<T>` instead, \
2809
- and only call `assume_init` after initialization is done",
2810
- ) ;
2811
- if let Some ( span) = init_error. span {
2812
- err. span_note ( span, & init_error. msg ) ;
2813
- } else {
2814
- err. note ( & init_error. msg ) ;
2815
- }
2816
- err. emit ( ) ;
2817
- } ) ;
2818
- }
2819
- }
2820
- }
2821
- }
2822
-
2823
2612
declare_lint ! {
2824
2613
/// The `clashing_extern_declarations` lint detects when an `extern fn`
2825
2614
/// has been declared with the same name but different types.
0 commit comments