1- use crate :: { lints:: FnNullCheckDiag , LateContext , LateLintPass , LintContext } ;
1+ use crate :: { lints:: NonNullCheckDiag , LateContext , LateLintPass , LintContext } ;
22use rustc_ast:: LitKind ;
33use rustc_hir:: { BinOpKind , Expr , ExprKind , TyKind } ;
4+ use rustc_middle:: ty:: Ty ;
45use rustc_session:: { declare_lint, declare_lint_pass} ;
56use rustc_span:: sym;
67
78declare_lint ! {
8- /// The `incorrect_fn_null_checks ` lint checks for expression that checks if a
9- /// function pointer is null.
9+ /// The `incorrect_non_null_checks ` lint checks for expressions that check if a
10+ /// non-nullable type is null.
1011 ///
1112 /// ### Example
1213 ///
@@ -22,85 +23,108 @@ declare_lint! {
2223 ///
2324 /// ### Explanation
2425 ///
25- /// Function pointers are assumed to be non- null, checking them for null will always
26- /// return false .
27- INCORRECT_FN_NULL_CHECKS ,
26+ /// A non-nullable type is assumed to never be null, and therefore having an actual
27+ /// non-null pointer is ub .
28+ INCORRECT_NON_NULL_CHECKS ,
2829 Warn ,
29- "incorrect checking of null function pointer "
30+ "incorrect checking of non null pointers "
3031}
3132
32- declare_lint_pass ! ( IncorrectFnNullChecks => [ INCORRECT_FN_NULL_CHECKS ] ) ;
33+ declare_lint_pass ! ( IncorrectNonNullChecks => [ INCORRECT_NON_NULL_CHECKS ] ) ;
3334
34- fn is_fn_ptr_cast ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
35+ /// Is the cast to a nonnull type?
36+ /// If yes, return (ty, nullable_version) where former is the nonnull type while latter
37+ /// is a nullable version (e.g. (fn, Option<fn>) or (&u8, *const u8)).
38+ fn is_nonnull_cast < ' a > ( cx : & LateContext < ' a > , expr : & Expr < ' _ > ) -> Option < Ty < ' a > > {
3539 let mut expr = expr. peel_blocks ( ) ;
3640 let mut had_at_least_one_cast = false ;
3741 while let ExprKind :: Cast ( cast_expr, cast_ty) = expr. kind
3842 && let TyKind :: Ptr ( _) = cast_ty. kind {
3943 expr = cast_expr. peel_blocks ( ) ;
4044 had_at_least_one_cast = true ;
4145 }
42- had_at_least_one_cast && cx. typeck_results ( ) . expr_ty_adjusted ( expr) . is_fn ( )
46+ if !had_at_least_one_cast {
47+ return None ;
48+ }
49+ let ty = cx. typeck_results ( ) . expr_ty_adjusted ( expr) ;
50+ if ty. is_fn ( ) || ty. is_ref ( ) {
51+ return Some ( ty) ;
52+ }
53+ // Usually, references get coerced to pointers in a casting situation.
54+ // Therefore, we give also give a look to the original type.
55+ let ty_unadjusted = cx. typeck_results ( ) . expr_ty_opt ( expr) ;
56+ if let Some ( ty_unadjusted) = ty_unadjusted && ty_unadjusted. is_ref ( ) {
57+ return Some ( ty_unadjusted) ;
58+ }
59+ None
4360}
4461
45- impl < ' tcx > LateLintPass < ' tcx > for IncorrectFnNullChecks {
62+ impl < ' tcx > LateLintPass < ' tcx > for IncorrectNonNullChecks {
4663 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
4764 match expr. kind {
4865 // Catching:
49- // <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>)
66+ // <*<const/mut> <ty>>::is_null(test_ptr as *<const/mut> <ty>)
5067 ExprKind :: Call ( path, [ arg] )
5168 if let ExprKind :: Path ( ref qpath) = path. kind
5269 && let Some ( def_id) = cx. qpath_res ( qpath, path. hir_id ) . opt_def_id ( )
5370 && matches ! (
5471 cx. tcx. get_diagnostic_name( def_id) ,
5572 Some ( sym:: ptr_const_is_null | sym:: ptr_is_null)
5673 )
57- && is_fn_ptr_cast ( cx, arg) =>
74+ && let Some ( ty ) = is_nonnull_cast ( cx, arg) =>
5875 {
59- cx. emit_spanned_lint ( INCORRECT_FN_NULL_CHECKS , expr. span , FnNullCheckDiag )
76+ let diag = NonNullCheckDiag { ty_desc : ty. prefix_string ( cx. tcx ) } ;
77+ cx. emit_spanned_lint ( INCORRECT_NON_NULL_CHECKS , expr. span , diag)
6078 }
6179
6280 // Catching:
63- // (fn_ptr as *<const/mut> <ty>).is_null()
81+ // (test_ptr as *<const/mut> <ty>).is_null()
6482 ExprKind :: MethodCall ( _, receiver, _, _)
6583 if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id )
6684 && matches ! (
6785 cx. tcx. get_diagnostic_name( def_id) ,
6886 Some ( sym:: ptr_const_is_null | sym:: ptr_is_null)
6987 )
70- && is_fn_ptr_cast ( cx, receiver) =>
88+ && let Some ( ty ) = is_nonnull_cast ( cx, receiver) =>
7189 {
72- cx. emit_spanned_lint ( INCORRECT_FN_NULL_CHECKS , expr. span , FnNullCheckDiag )
90+ let diag = NonNullCheckDiag { ty_desc : ty. prefix_string ( cx. tcx ) } ;
91+ cx. emit_spanned_lint ( INCORRECT_NON_NULL_CHECKS , expr. span , diag)
7392 }
7493
7594 ExprKind :: Binary ( op, left, right) if matches ! ( op. node, BinOpKind :: Eq ) => {
7695 let to_check: & Expr < ' _ > ;
77- if is_fn_ptr_cast ( cx, left) {
96+ let ty: Ty < ' _ > ;
97+ if let Some ( ty_) = is_nonnull_cast ( cx, left) {
7898 to_check = right;
79- } else if is_fn_ptr_cast ( cx, right) {
99+ ty = ty_;
100+ } else if let Some ( ty_) = is_nonnull_cast ( cx, right) {
80101 to_check = left;
102+ ty = ty_;
81103 } else {
82104 return ;
83105 }
84106
85107 match to_check. kind {
86108 // Catching:
87- // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
109+ // (test_ptr as *<const/mut> <ty>) == (0 as <ty>)
88110 ExprKind :: Cast ( cast_expr, _)
89111 if let ExprKind :: Lit ( spanned) = cast_expr. kind
90112 && let LitKind :: Int ( v, _) = spanned. node && v == 0 =>
91113 {
92- cx. emit_spanned_lint ( INCORRECT_FN_NULL_CHECKS , expr. span , FnNullCheckDiag )
114+ let diag = NonNullCheckDiag { ty_desc : ty. prefix_string ( cx. tcx ) } ;
115+ cx. emit_spanned_lint ( INCORRECT_NON_NULL_CHECKS , expr. span , diag)
93116 } ,
94117
95118 // Catching:
96- // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
119+ // (test_ptr as *<const/mut> <ty>) == std::ptr::null()
97120 ExprKind :: Call ( path, [ ] )
98121 if let ExprKind :: Path ( ref qpath) = path. kind
99122 && let Some ( def_id) = cx. qpath_res ( qpath, path. hir_id ) . opt_def_id ( )
100123 && let Some ( diag_item) = cx. tcx . get_diagnostic_name ( def_id)
101124 && ( diag_item == sym:: ptr_null || diag_item == sym:: ptr_null_mut) =>
102125 {
103- cx. emit_spanned_lint ( INCORRECT_FN_NULL_CHECKS , expr. span , FnNullCheckDiag )
126+ let diag = NonNullCheckDiag { ty_desc : ty. prefix_string ( cx. tcx ) } ;
127+ cx. emit_spanned_lint ( INCORRECT_NON_NULL_CHECKS , expr. span , diag)
104128 } ,
105129
106130 _ => { } ,
0 commit comments