about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2023-02-26 02:55:52 -0500
committerJason Newcomb <jsnewcomb@pm.me>2023-02-26 02:55:52 -0500
commit002e9341891c95886b3eb29dfa9be1d50d8096d4 (patch)
tree79a3f645051d6ab41cc1f6371f41625163293484
parent3d193fa17a7df3256d58b841a2df92af1cbdbea4 (diff)
downloadrust-002e9341891c95886b3eb29dfa9be1d50d8096d4.tar.gz
rust-002e9341891c95886b3eb29dfa9be1d50d8096d4.zip
Don't assume paths work with `fn_sig` in `multiple_unsafe_ops_pre_block`.
-rw-r--r--clippy_lints/src/multiple_unsafe_ops_per_block.rs37
-rw-r--r--tests/ui/multiple_unsafe_ops_per_block.rs28
-rw-r--r--tests/ui/multiple_unsafe_ops_per_block.stderr62
3 files changed, 99 insertions, 28 deletions
diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 63c575fca30..5418616ded0 100644
--- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -11,6 +11,7 @@ use rustc_ast::Mutability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
@@ -120,33 +121,15 @@ fn collect_unsafe_exprs<'tcx>(
                 unsafe_ops.push(("raw pointer dereference occurs here", expr.span));
             },
 
-            ExprKind::Call(path_expr, _) => match path_expr.kind {
-                ExprKind::Path(QPath::Resolved(
-                    _,
-                    hir::Path {
-                        res: Res::Def(kind, def_id),
-                        ..
-                    },
-                )) if kind.is_fn_like() => {
-                    let sig = cx.tcx.fn_sig(*def_id);
-                    if sig.0.unsafety() == Unsafety::Unsafe {
-                        unsafe_ops.push(("unsafe function call occurs here", expr.span));
-                    }
-                },
-
-                ExprKind::Path(QPath::TypeRelative(..)) => {
-                    if let Some(sig) = cx
-                        .typeck_results()
-                        .type_dependent_def_id(path_expr.hir_id)
-                        .map(|def_id| cx.tcx.fn_sig(def_id))
-                    {
-                        if sig.0.unsafety() == Unsafety::Unsafe {
-                            unsafe_ops.push(("unsafe function call occurs here", expr.span));
-                        }
-                    }
-                },
-
-                _ => {},
+            ExprKind::Call(path_expr, _) => {
+                let sig = match *cx.typeck_results().expr_ty(path_expr).kind() {
+                    ty::FnDef(id, _) => cx.tcx.fn_sig(id).skip_binder(),
+                    ty::FnPtr(sig) => sig,
+                    _ => return Continue(Descend::Yes),
+                };
+                if sig.unsafety() == Unsafety::Unsafe {
+                    unsafe_ops.push(("unsafe function call occurs here", expr.span));
+                }
             },
 
             ExprKind::MethodCall(..) => {
diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs
index 4511bc99c3c..5073685c9f0 100644
--- a/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -116,4 +116,32 @@ fn issue10259() {
     unsafe_macro!();
 }
 
+fn _fn_ptr(x: unsafe fn()) {
+    unsafe {
+        x();
+        x();
+    }
+}
+
+fn _assoc_const() {
+    trait X {
+        const X: unsafe fn();
+    }
+    fn _f<T: X>() {
+        unsafe {
+            T::X();
+            T::X();
+        }
+    }
+}
+
+fn _field_fn_ptr(x: unsafe fn()) {
+    struct X(unsafe fn());
+    let x = X(x);
+    unsafe {
+        x.0();
+        x.0();
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr
index 303aeb7aee0..e0c1d3801f7 100644
--- a/tests/ui/multiple_unsafe_ops_per_block.stderr
+++ b/tests/ui/multiple_unsafe_ops_per_block.stderr
@@ -125,5 +125,65 @@ note: raw pointer dereference occurs here
 LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
    |                                       ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:120:5
+   |
+LL | /     unsafe {
+LL | |         x();
+LL | |         x();
+LL | |     }
+   | |_____^
+   |
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:121:9
+   |
+LL |         x();
+   |         ^^^
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:122:9
+   |
+LL |         x();
+   |         ^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:131:9
+   |
+LL | /         unsafe {
+LL | |             T::X();
+LL | |             T::X();
+LL | |         }
+   | |_________^
+   |
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:132:13
+   |
+LL |             T::X();
+   |             ^^^^^^
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:133:13
+   |
+LL |             T::X();
+   |             ^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:141:5
+   |
+LL | /     unsafe {
+LL | |         x.0();
+LL | |         x.0();
+LL | |     }
+   | |_____^
+   |
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:142:9
+   |
+LL |         x.0();
+   |         ^^^^^
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:143:9
+   |
+LL |         x.0();
+   |         ^^^^^
+
+error: aborting due to 8 previous errors