about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2022-07-02 00:59:58 -0400
committerJason Newcomb <jsnewcomb@pm.me>2022-07-02 00:59:58 -0400
commit3e80d3988d70847e6b870749641ea6d434ff261b (patch)
tree55461fd5852d96d93378e18b65e39316473384bd
parent8c341d66a1203d58e53fad206a131357550b2d7b (diff)
downloadrust-3e80d3988d70847e6b870749641ea6d434ff261b.tar.gz
rust-3e80d3988d70847e6b870749641ea6d434ff261b.zip
Fix ICE in `dereference.rs`
-rw-r--r--clippy_lints/src/dereference.rs40
-rw-r--r--tests/ui/explicit_auto_deref.fixed4
-rw-r--r--tests/ui/explicit_auto_deref.rs4
-rw-r--r--tests/ui/explicit_auto_deref.stderr8
4 files changed, 42 insertions, 14 deletions
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 59dcc1ebf19..14e8d5940cf 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, GenericArg, HirId, ImplItem,
+    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, FnRetTy, GenericArg, HirId, ImplItem,
     ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
     TraitItemKind, TyKind, UnOp,
 };
@@ -717,18 +717,32 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
 
             Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
                 ExprKind::Ret(_) => {
-                    let output = cx
-                        .tcx
-                        .fn_sig(cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()))
-                        .skip_binder()
-                        .output();
-                    Some(if !output.is_ref() {
-                        Position::Other(precedence)
-                    } else if output.has_placeholders() || output.has_opaque_types() {
-                        Position::ReborrowStable(precedence)
-                    } else {
-                        Position::DerefStable(precedence)
-                    })
+                    let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
+                    Some(
+                        if let Node::Expr(Expr {
+                            kind: ExprKind::Closure { fn_decl, .. },
+                            ..
+                        }) = cx.tcx.hir().get(owner_id)
+                        {
+                            match fn_decl.output {
+                                FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence),
+                                FnRetTy::DefaultReturn(_) => Position::Other(precedence),
+                            }
+                        } else {
+                            let output = cx
+                                .tcx
+                                .fn_sig(cx.tcx.hir().local_def_id(owner_id))
+                                .skip_binder()
+                                .output();
+                            if !output.is_ref() {
+                                Position::Other(precedence)
+                            } else if output.has_placeholders() || output.has_opaque_types() {
+                                Position::ReborrowStable(precedence)
+                            } else {
+                                Position::DerefStable(precedence)
+                            }
+                        },
+                    )
                 },
                 ExprKind::Call(func, _) if func.hir_id == child_id => (child_id == e.hir_id).then(|| Position::Callee),
                 ExprKind::Call(func, args) => args
diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed
index d4ff1b1566d..a650fdc1f89 100644
--- a/tests/ui/explicit_auto_deref.fixed
+++ b/tests/ui/explicit_auto_deref.fixed
@@ -211,4 +211,8 @@ fn main() {
     unsafe {
         var(0, &**x);
     }
+
+    let s = &"str";
+    let _ = || return *s;
+    let _ = || -> &'static str { return s };
 }
diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs
index 99294a7947b..8f4f352576a 100644
--- a/tests/ui/explicit_auto_deref.rs
+++ b/tests/ui/explicit_auto_deref.rs
@@ -211,4 +211,8 @@ fn main() {
     unsafe {
         var(0, &**x);
     }
+
+    let s = &"str";
+    let _ = || return *s;
+    let _ = || -> &'static str { return *s };
 }
diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr
index 55f956e37ae..92765307ea7 100644
--- a/tests/ui/explicit_auto_deref.stderr
+++ b/tests/ui/explicit_auto_deref.stderr
@@ -192,5 +192,11 @@ error: deref which would be done by auto-deref
 LL |     f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
    |            ^^^^^^^^^^ help: try this: `ref_str`
 
-error: aborting due to 32 previous errors
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:217:41
+   |
+LL |     let _ = || -> &'static str { return *s };
+   |                                         ^^ help: try this: `s`
+
+error: aborting due to 33 previous errors