From 237e52478732424736f9f7e4c941844ba421ce18 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 24 Feb 2021 21:30:39 +0100
Subject: [PATCH] Fix impl being removed excessively

---
 src/librustdoc/passes/collect_trait_impls.rs | 25 +++++++++++++------
 src/test/rustdoc/impl-on-foreign.rs          | 26 ++++++++++++++++++++
 2 files changed, 44 insertions(+), 7 deletions(-)
 create mode 100644 src/test/rustdoc/impl-on-foreign.rs

diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 0271a5b78a7ef..bc90ac0818618 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -88,18 +88,29 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
 
     let mut cleaner = BadImplStripper { prims, items: crate_items };
 
+    let sized_trait = cx.tcx.lang_items().sized_trait();
+    let deref_trait = cx.tcx.lang_items().deref_trait();
+
     let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
     // Gather all type to `Deref` target edges.
     for it in &new_items {
         if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
-            if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
-                let target = items.iter().find_map(|item| match *item.kind {
-                    TypedefItem(ref t, true) => Some(&t.type_),
-                    _ => None,
-                });
-                if let (Some(for_did), Some(target)) = (for_.def_id(), target) {
-                    type_did_to_deref_target.insert(for_did, target);
+            match trait_.def_id() {
+                did if sized_trait == did => {}
+                Some(did) => {
+                    if Some(did) == deref_trait {
+                        let target = items.iter().find_map(|item| match *item.kind {
+                            TypedefItem(ref t, true) => Some(&t.type_),
+                            _ => None,
+                        });
+                        if let (Some(for_did), Some(target)) = (for_.def_id(), target) {
+                            type_did_to_deref_target.insert(for_did, target);
+                        }
+                    } else {
+                        cleaner.items.insert(did);
+                    }
                 }
+                _ => {}
             }
         }
     }
diff --git a/src/test/rustdoc/impl-on-foreign.rs b/src/test/rustdoc/impl-on-foreign.rs
new file mode 100644
index 0000000000000..2a638e16e5fa4
--- /dev/null
+++ b/src/test/rustdoc/impl-on-foreign.rs
@@ -0,0 +1,26 @@
+#![crate_name = "foo"]
+
+use std::convert::AsRef;
+pub struct Gus;
+
+// @has 'foo/struct.Gus.html'
+// @has - '//h3[@class="impl"]/code' 'impl AsRef<str> for Gus'
+impl AsRef<str> for Gus {
+    fn as_ref(&self) -> &str {
+        todo!()
+    }
+}
+
+// @has - '//h3[@class="impl"]/code' 'impl AsRef<Gus> for str'
+impl AsRef<Gus> for str {
+    fn as_ref(&self) -> &Gus {
+        todo!()
+    }
+}
+
+// @has - '//h3[@class="impl"]/code' 'impl AsRef<Gus> for String'
+impl AsRef<Gus> for String {
+    fn as_ref(&self) -> &Gus {
+        todo!()
+    }
+}