about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-26 16:33:30 +0000
committerbors <bors@rust-lang.org>2022-05-26 16:33:30 +0000
commit6553b985408dba318cd93b96eb9ce2b858100635 (patch)
treee3563f1c210573dc3b2cf32693c9e8723b9aaf8a
parentbc4d39e5fea64970dded1e6d2132d41435c0ef24 (diff)
parent17f70478116d3b77783db2ed6453697a77a7d769 (diff)
Auto merge of #8896 - Alexendoo:fn_sig_ice, r=llogiq
Only return `DefId`s to `Fn`-like definitions in `clippy_utils::fn_def_id`

Fixes #8850

in `returns.rs` `tcx.fn_sig` is called on the result of `fn_def_id`, which panics if the def is a `const`/`static`/etc rather than a functions definition

https://github.com/rust-lang/rust-clippy/blob/bc4d39e5fea64970dded1e6d2132d41435c0ef24/clippy_lints/src/returns.rs#L294-L303

changelog: Fix ICE due to callable `static`/`const`s
-rw-r--r--clippy_utils/src/lib.rs12
-rw-r--r--tests/ui/crashes/ice-8850.rs27
-rw-r--r--tests/ui/crashes/ice-8850.stderr45
3 files changed, 83 insertions, 1 deletions
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index adb37cc9d75..b8a80d4adc3 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1916,7 +1916,17 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
                 ..
             },
             ..,
-        ) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(),
+        ) => {
+            // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
+            // deref to fn pointers, dyn Fn, impl Fn - #8850
+            if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
+                cx.typeck_results().qpath_res(qpath, *path_hir_id)
+            {
+                Some(id)
+            } else {
+                None
+            }
+        },
         _ => None,
     }
 }
diff --git a/tests/ui/crashes/ice-8850.rs b/tests/ui/crashes/ice-8850.rs
new file mode 100644
index 00000000000..f2747ab2239
--- /dev/null
+++ b/tests/ui/crashes/ice-8850.rs
@@ -0,0 +1,27 @@
+fn fn_pointer_static() -> usize {
+    static FN: fn() -> usize = || 1;
+    let res = FN() + 1;
+    res
+}
+
+fn fn_pointer_const() -> usize {
+    const FN: fn() -> usize = || 1;
+    let res = FN() + 1;
+    res
+}
+
+fn deref_to_dyn_fn() -> usize {
+    struct Derefs;
+    impl std::ops::Deref for Derefs {
+        type Target = dyn Fn() -> usize;
+
+        fn deref(&self) -> &Self::Target {
+            &|| 2
+        }
+    }
+    static FN: Derefs = Derefs;
+    let res = FN() + 1;
+    res
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-8850.stderr b/tests/ui/crashes/ice-8850.stderr
new file mode 100644
index 00000000000..620fd1edaf7
--- /dev/null
+++ b/tests/ui/crashes/ice-8850.stderr
@@ -0,0 +1,45 @@
+error: returning the result of a `let` binding from a block
+  --> $DIR/ice-8850.rs:4:5
+   |
+LL |     let res = FN() + 1;
+   |     ------------------- unnecessary `let` binding
+LL |     res
+   |     ^^^
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+help: return the expression directly
+   |
+LL ~     
+LL ~     FN() + 1
+   |
+
+error: returning the result of a `let` binding from a block
+  --> $DIR/ice-8850.rs:10:5
+   |
+LL |     let res = FN() + 1;
+   |     ------------------- unnecessary `let` binding
+LL |     res
+   |     ^^^
+   |
+help: return the expression directly
+   |
+LL ~     
+LL ~     FN() + 1
+   |
+
+error: returning the result of a `let` binding from a block
+  --> $DIR/ice-8850.rs:24:5
+   |
+LL |     let res = FN() + 1;
+   |     ------------------- unnecessary `let` binding
+LL |     res
+   |     ^^^
+   |
+help: return the expression directly
+   |
+LL ~     
+LL ~     FN() + 1
+   |
+
+error: aborting due to 3 previous errors
+