@@ -951,6 +951,38 @@ declare_clippy_lint! {
951951 "suspicious usage of map"
952952}
953953
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+
954986declare_lint_pass ! ( Methods => [
955987 OPTION_UNWRAP_USED ,
956988 RESULT_UNWRAP_USED ,
@@ -991,6 +1023,7 @@ declare_lint_pass!(Methods => [
9911023 INTO_ITER_ON_ARRAY ,
9921024 INTO_ITER_ON_REF ,
9931025 SUSPICIOUS_MAP ,
1026+ UNINIT_ASSUMED_INIT ,
9941027] ) ;
9951028
9961029impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Methods {
@@ -1038,6 +1071,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
10381071 [ "fold" , ..] => lint_unnecessary_fold ( cx, expr, arg_lists[ 0 ] ) ,
10391072 [ "filter_map" , ..] => unnecessary_filter_map:: lint ( cx, expr, arg_lists[ 0 ] ) ,
10401073 [ "count" , "map" ] => lint_suspicious_map ( cx, expr) ,
1074+ [ "assume_init" ] => lint_maybe_uninit ( cx, & arg_lists[ 0 ] [ 0 ] , expr) ,
10411075 _ => { } ,
10421076 }
10431077
@@ -2662,6 +2696,37 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_
26622696 }
26632697}
26642698
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+
26652730fn lint_suspicious_map ( cx : & LateContext < ' _ , ' _ > , expr : & hir:: Expr ) {
26662731 span_help_and_lint (
26672732 cx,
0 commit comments