@@ -951,6 +951,38 @@ declare_clippy_lint! {
951
951
"suspicious usage of map"
952
952
}
953
953
954
+ declare_clippy_lint ! {
955
+ /// **What it does:** Checks for `MaybeUninit::uninit().assume_init()`.
956
+ ///
957
+ /// **Why is this bad?** For most types, this is undefined behavior.
958
+ ///
959
+ /// **Known problems:** For now, we accept empty tuples and tuples / arrays
960
+ /// of `MaybeUninit`. There may be other types that allow uninitialized
961
+ /// data, but those are not yet rigorously defined.
962
+ ///
963
+ /// **Example:**
964
+ ///
965
+ /// ```rust
966
+ /// // Beware the UB
967
+ /// use std::mem::MaybeUninit;
968
+ ///
969
+ /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
970
+ /// ```
971
+ ///
972
+ /// Note that the following is OK:
973
+ ///
974
+ /// ```rust
975
+ /// use std::mem::MaybeUninit;
976
+ ///
977
+ /// let _: [MaybeUninit<bool>; 5] = unsafe {
978
+ /// MaybeUninit::uninit().assume_init()
979
+ /// };
980
+ /// ```
981
+ pub UNINIT_ASSUMED_INIT ,
982
+ correctness,
983
+ "`MaybeUninit::uninit().assume_init()`"
984
+ }
985
+
954
986
declare_lint_pass ! ( Methods => [
955
987
OPTION_UNWRAP_USED ,
956
988
RESULT_UNWRAP_USED ,
@@ -991,6 +1023,7 @@ declare_lint_pass!(Methods => [
991
1023
INTO_ITER_ON_ARRAY ,
992
1024
INTO_ITER_ON_REF ,
993
1025
SUSPICIOUS_MAP ,
1026
+ UNINIT_ASSUMED_INIT ,
994
1027
] ) ;
995
1028
996
1029
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Methods {
@@ -1038,6 +1071,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
1038
1071
[ "fold" , ..] => lint_unnecessary_fold ( cx, expr, arg_lists[ 0 ] ) ,
1039
1072
[ "filter_map" , ..] => unnecessary_filter_map:: lint ( cx, expr, arg_lists[ 0 ] ) ,
1040
1073
[ "count" , "map" ] => lint_suspicious_map ( cx, expr) ,
1074
+ [ "assume_init" ] => lint_maybe_uninit ( cx, & arg_lists[ 0 ] [ 0 ] , expr) ,
1041
1075
_ => { } ,
1042
1076
}
1043
1077
@@ -2662,6 +2696,37 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_
2662
2696
}
2663
2697
}
2664
2698
2699
+ /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
2700
+ fn lint_maybe_uninit ( cx : & LateContext < ' _ , ' _ > , expr : & hir:: Expr , outer : & hir:: Expr ) {
2701
+ if_chain ! {
2702
+ if let hir:: ExprKind :: Call ( ref callee, ref args) = expr. node;
2703
+ if args. is_empty( ) ;
2704
+ if let hir:: ExprKind :: Path ( ref path) = callee. node;
2705
+ if match_qpath( path, & paths:: MEM_MAYBEUNINIT_UNINIT ) ;
2706
+ if !is_maybe_uninit_ty_valid( cx, cx. tables. expr_ty_adjusted( outer) ) ;
2707
+ then {
2708
+ span_lint(
2709
+ cx,
2710
+ UNINIT_ASSUMED_INIT ,
2711
+ outer. span,
2712
+ "this call for this type may be undefined behavior"
2713
+ ) ;
2714
+ }
2715
+ }
2716
+ }
2717
+
2718
+ fn is_maybe_uninit_ty_valid ( cx : & LateContext < ' _ , ' _ > , ty : Ty < ' _ > ) -> bool {
2719
+ match ty. sty {
2720
+ ty:: Array ( ref component, _) => is_maybe_uninit_ty_valid ( cx, component) ,
2721
+ ty:: Tuple ( ref types) => types. types ( ) . all ( |ty| is_maybe_uninit_ty_valid ( cx, ty) ) ,
2722
+ ty:: Adt ( ref adt, _) => {
2723
+ // needs to be a MaybeUninit
2724
+ match_def_path ( cx, adt. did , & paths:: MEM_MAYBEUNINIT )
2725
+ } ,
2726
+ _ => false ,
2727
+ }
2728
+ }
2729
+
2665
2730
fn lint_suspicious_map ( cx : & LateContext < ' _ , ' _ > , expr : & hir:: Expr ) {
2666
2731
span_help_and_lint (
2667
2732
cx,
0 commit comments