about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUrgau <urgau@numericable.fr>2023-07-13 14:13:08 +0200
committerUrgau <urgau@numericable.fr>2023-08-03 10:52:15 +0200
commit4b3dadbe5a9f3dd06932a9099abd37bae751cdd3 (patch)
tree194edafcf22e303b1e9b1fa8aaafa097b01ae24f
parent0b9529cca39d86138066012e85cae96ba4a7c253 (diff)
downloadrust-4b3dadbe5a9f3dd06932a9099abd37bae751cdd3.tar.gz
rust-4b3dadbe5a9f3dd06932a9099abd37bae751cdd3.zip
Also lint on cast/cast_mut and ptr::from_mut/ptr::from_ref
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs52
-rw-r--r--tests/ui/consts/ptr_is_null.rs1
-rw-r--r--tests/ui/lint/ptr_null_checks.rs16
-rw-r--r--tests/ui/lint/ptr_null_checks.stderr88
4 files changed, 121 insertions, 36 deletions
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index b2138c42224..64b86fec46b 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -31,25 +31,45 @@ declare_lint! {
 
 declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
 
-fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<PtrNullChecksDiag<'a>> {
-    let mut expr = expr.peel_blocks();
+/// This function detects and returns the original expression from a series of consecutive casts,
+/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
+fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
     let mut had_at_least_one_cast = false;
-    while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
-            && let TyKind::Ptr(_) = cast_ty.kind {
-        expr = cast_expr.peel_blocks();
-        had_at_least_one_cast = true;
+    loop {
+        e = e.peel_blocks();
+        e = if let ExprKind::Cast(expr, t) = e.kind
+            && let TyKind::Ptr(_) = t.kind {
+            had_at_least_one_cast = true;
+            expr
+        } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
+            && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+            && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
+            had_at_least_one_cast = true;
+            expr
+        } else if let ExprKind::Call(path, [arg]) = e.kind
+            && let ExprKind::Path(ref qpath) = path.kind
+            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+            && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::ptr_from_mut)) {
+            had_at_least_one_cast = true;
+            arg
+        } else if had_at_least_one_cast {
+            return Some(e);
+        } else {
+            return None;
+        };
     }
-    if !had_at_least_one_cast {
-        None
+}
+
+fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<PtrNullChecksDiag<'a>> {
+    let expr = ptr_cast_chain(cx, expr)?;
+
+    let orig_ty = cx.typeck_results().expr_ty(expr);
+    if orig_ty.is_fn() {
+        Some(PtrNullChecksDiag::FnPtr)
+    } else if orig_ty.is_ref() {
+        Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span })
     } else {
-        let orig_ty = cx.typeck_results().expr_ty(expr);
-        if orig_ty.is_fn() {
-            Some(PtrNullChecksDiag::FnPtr)
-        } else if orig_ty.is_ref() {
-            Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span })
-        } else {
-            None
-        }
+        None
     }
 }
 
diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs
index 8babb68585d..43b9767db16 100644
--- a/tests/ui/consts/ptr_is_null.rs
+++ b/tests/ui/consts/ptr_is_null.rs
@@ -2,6 +2,7 @@
 // check-pass
 
 #![feature(const_ptr_is_null)]
+#![allow(useless_ptr_null_checks)]
 
 const FOO: &usize = &42;
 
diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs
index 600ca32ca89..e677ea3094d 100644
--- a/tests/ui/lint/ptr_null_checks.rs
+++ b/tests/ui/lint/ptr_null_checks.rs
@@ -1,5 +1,9 @@
 // check-pass
 
+#![feature(ptr_from_ref)]
+
+use std::ptr;
+
 extern "C" fn c_fn() {}
 fn static_i32() -> &'static i32 { &1 }
 
@@ -21,6 +25,10 @@ fn main() {
     //~^ WARN function pointers are not nullable
     if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
     //~^ WARN function pointers are not nullable
+    if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {}
+    //~^ WARN function pointers are not nullable
+    if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {}
+    //~^ WARN function pointers are not nullable
     if (fn_ptr as fn() as *const ()).is_null() {}
     //~^ WARN function pointers are not nullable
     if (c_fn as *const fn()).is_null() {}
@@ -29,8 +37,16 @@ fn main() {
     // ---------------- References ------------------
     if (&mut 8 as *mut i32).is_null() {}
     //~^ WARN references are not nullable
+    if ptr::from_mut(&mut 8).is_null() {}
+    //~^ WARN references are not nullable
     if (&8 as *const i32).is_null() {}
     //~^ WARN references are not nullable
+    if ptr::from_ref(&8).is_null() {}
+    //~^ WARN references are not nullable
+    if ptr::from_ref(&8).cast_mut().is_null() {}
+    //~^ WARN references are not nullable
+    if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
+    //~^ WARN references are not nullable
     if (&8 as *const i32) == std::ptr::null() {}
     //~^ WARN references are not nullable
     let ref_num = &8;
diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr
index 10efa8685be..525d96c4919 100644
--- a/tests/ui/lint/ptr_null_checks.stderr
+++ b/tests/ui/lint/ptr_null_checks.stderr
@@ -1,5 +1,5 @@
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:10:8
+  --> $DIR/ptr_null_checks.rs:14:8
    |
 LL |     if (fn_ptr as *mut ()).is_null() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     if (fn_ptr as *mut ()).is_null() {}
    = note: `#[warn(useless_ptr_null_checks)]` on by default
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:12:8
+  --> $DIR/ptr_null_checks.rs:16:8
    |
 LL |     if (fn_ptr as *const u8).is_null() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     if (fn_ptr as *const u8).is_null() {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:14:8
+  --> $DIR/ptr_null_checks.rs:18:8
    |
 LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:16:8
+  --> $DIR/ptr_null_checks.rs:20:8
    |
 LL |     if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL |     if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:18:8
+  --> $DIR/ptr_null_checks.rs:22:8
    |
 LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:20:8
+  --> $DIR/ptr_null_checks.rs:24:8
    |
 LL |     if <*const _>::is_null(fn_ptr as *const ()) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     if <*const _>::is_null(fn_ptr as *const ()) {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:22:8
+  --> $DIR/ptr_null_checks.rs:26:8
    |
 LL |     if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -56,7 +56,23 @@ LL |     if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:24:8
+  --> $DIR/ptr_null_checks.rs:28:8
+   |
+LL |     if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:30:8
+   |
+LL |     if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:32:8
    |
 LL |     if (fn_ptr as fn() as *const ()).is_null() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +80,7 @@ LL |     if (fn_ptr as fn() as *const ()).is_null() {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:26:8
+  --> $DIR/ptr_null_checks.rs:34:8
    |
 LL |     if (c_fn as *const fn()).is_null() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +88,7 @@ LL |     if (c_fn as *const fn()).is_null() {}
    = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:30:8
+  --> $DIR/ptr_null_checks.rs:38:8
    |
 LL |     if (&mut 8 as *mut i32).is_null() {}
    |        ^------^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,7 +96,15 @@ LL |     if (&mut 8 as *mut i32).is_null() {}
    |         expression has type `&mut i32`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:32:8
+  --> $DIR/ptr_null_checks.rs:40:8
+   |
+LL |     if ptr::from_mut(&mut 8).is_null() {}
+   |        ^^^^^^^^^^^^^^------^^^^^^^^^^^
+   |                      |
+   |                      expression has type `&mut i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:42:8
    |
 LL |     if (&8 as *const i32).is_null() {}
    |        ^--^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -88,7 +112,31 @@ LL |     if (&8 as *const i32).is_null() {}
    |         expression has type `&i32`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:34:8
+  --> $DIR/ptr_null_checks.rs:44:8
+   |
+LL |     if ptr::from_ref(&8).is_null() {}
+   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^
+   |                      |
+   |                      expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:46:8
+   |
+LL |     if ptr::from_ref(&8).cast_mut().is_null() {}
+   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^
+   |                      |
+   |                      expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:48:8
+   |
+LL |     if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
+   |        ^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       |
+   |                       expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:50:8
    |
 LL |     if (&8 as *const i32) == std::ptr::null() {}
    |        ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +144,7 @@ LL |     if (&8 as *const i32) == std::ptr::null() {}
    |         expression has type `&i32`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:37:8
+  --> $DIR/ptr_null_checks.rs:53:8
    |
 LL |     if (ref_num as *const i32) == std::ptr::null() {}
    |        ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +152,7 @@ LL |     if (ref_num as *const i32) == std::ptr::null() {}
    |         expression has type `&i32`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:39:8
+  --> $DIR/ptr_null_checks.rs:55:8
    |
 LL |     if (b"\0" as *const u8).is_null() {}
    |        ^-----^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +160,7 @@ LL |     if (b"\0" as *const u8).is_null() {}
    |         expression has type `&[u8; 1]`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:41:8
+  --> $DIR/ptr_null_checks.rs:57:8
    |
 LL |     if ("aa" as *const str).is_null() {}
    |        ^----^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +168,7 @@ LL |     if ("aa" as *const str).is_null() {}
    |         expression has type `&str`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:43:8
+  --> $DIR/ptr_null_checks.rs:59:8
    |
 LL |     if (&[1, 2] as *const i32).is_null() {}
    |        ^-------^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,7 +176,7 @@ LL |     if (&[1, 2] as *const i32).is_null() {}
    |         expression has type `&[i32; 2]`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:45:8
+  --> $DIR/ptr_null_checks.rs:61:8
    |
 LL |     if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {}
    |        ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +184,7 @@ LL |     if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {}
    |         expression has type `&mut [i32; 2]`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:47:8
+  --> $DIR/ptr_null_checks.rs:63:8
    |
 LL |     if (static_i32() as *const i32).is_null() {}
    |        ^------------^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -144,12 +192,12 @@ LL |     if (static_i32() as *const i32).is_null() {}
    |         expression has type `&i32`
 
 warning: references are not nullable, so checking them for null will always return false
-  --> $DIR/ptr_null_checks.rs:49:8
+  --> $DIR/ptr_null_checks.rs:65:8
    |
 LL |     if (&*{ static_i32() } as *const i32).is_null() {}
    |        ^------------------^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
    |         expression has type `&i32`
 
-warning: 19 warnings emitted
+warning: 25 warnings emitted