From 28e0c5aec8335d34cd84f3970d633860d6bd08a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?=
 <liehr.exchange@gmx.net>
Date: Fri, 16 Sep 2022 00:06:25 +0200
Subject: [PATCH] Allow more !Copy impls

---
 .../rustc_typeck/src/coherence/builtin.rs     | 18 ++++------
 .../coherence-negative-impls-copy-bad.rs      | 11 ++++++
 .../coherence-negative-impls-copy-bad.stderr  | 36 +++++++++++++++++++
 .../coherence-negative-impls-copy.rs          | 29 +++++++++++++++
 .../ui/coherence/deep-bad-copy-reason.stderr  |  4 +--
 src/test/ui/opt-in-copy.stderr                |  8 ++---
 src/test/ui/span/E0204.stderr                 |  8 ++---
 ...missing-bound-in-manual-copy-impl-2.stderr |  4 +--
 .../missing-bound-in-manual-copy-impl.stderr  |  4 +--
 .../traits/copy-impl-cannot-normalize.stderr  |  4 +--
 src/test/ui/union/union-copy.stderr           |  4 +--
 11 files changed, 100 insertions(+), 30 deletions(-)
 create mode 100644 src/test/ui/coherence/coherence-negative-impls-copy-bad.rs
 create mode 100644 src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr
 create mode 100644 src/test/ui/coherence/coherence-negative-impls-copy.rs

diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index d08c0d4dbb72a..d4eb826f0b4d3 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -70,23 +70,21 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     let self_type = tcx.type_of(impl_did);
     debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
 
-    let span = tcx.hir().span(impl_hir_id);
     let param_env = tcx.param_env(impl_did);
     assert!(!self_type.has_escaping_bound_vars());
 
     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
+    let span = match tcx.hir().expect_item(impl_did).kind {
+        ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return,
+        ItemKind::Impl(impl_) => impl_.self_ty.span,
+        _ => bug!("expected Copy impl item"),
+    };
+
     let cause = traits::ObligationCause::misc(span, impl_hir_id);
     match can_type_implement_copy(tcx, param_env, self_type, cause) {
         Ok(()) => {}
         Err(CopyImplementationError::InfrigingFields(fields)) => {
-            let item = tcx.hir().expect_item(impl_did);
-            let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
-                tr.path.span
-            } else {
-                span
-            };
-
             let mut err = struct_span_err!(
                 tcx.sess,
                 span,
@@ -166,10 +164,6 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
             err.emit();
         }
         Err(CopyImplementationError::NotAnAdt) => {
-            let item = tcx.hir().expect_item(impl_did);
-            let span =
-                if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
-
             tcx.sess.emit_err(CopyImplOnNonAdt { span });
         }
         Err(CopyImplementationError::HasDestructor) => {
diff --git a/src/test/ui/coherence/coherence-negative-impls-copy-bad.rs b/src/test/ui/coherence/coherence-negative-impls-copy-bad.rs
new file mode 100644
index 0000000000000..563f28e2291d4
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-impls-copy-bad.rs
@@ -0,0 +1,11 @@
+#![feature(negative_impls)]
+#![crate_type = "lib"]
+
+impl !Copy for str {}
+//~^ ERROR only traits defined in the current crate can be implemented
+
+impl !Copy for fn() {}
+//~^ ERROR only traits defined in the current crate can be implemented
+
+impl !Copy for () {}
+//~^ ERROR only traits defined in the current crate can be implemented
diff --git a/src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr b/src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr
new file mode 100644
index 0000000000000..2295d6315d1c2
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr
@@ -0,0 +1,36 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-negative-impls-copy-bad.rs:4:1
+   |
+LL | impl !Copy for str {}
+   | ^^^^^^^^^^^^^^^---
+   | |              |
+   | |              `str` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-negative-impls-copy-bad.rs:7:1
+   |
+LL | impl !Copy for fn() {}
+   | ^^^^^^^^^^^^^^^----
+   | |              |
+   | |              `fn()` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-negative-impls-copy-bad.rs:10:1
+   |
+LL | impl !Copy for () {}
+   | ^^^^^^^^^^^^^^^--
+   | |              |
+   | |              this is not defined in the current crate because tuples are always foreign
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/coherence-negative-impls-copy.rs b/src/test/ui/coherence/coherence-negative-impls-copy.rs
new file mode 100644
index 0000000000000..7b29aade41335
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-impls-copy.rs
@@ -0,0 +1,29 @@
+// check-pass
+// regression test for issue #101836
+
+#![feature(negative_impls, extern_types)]
+#![crate_type = "lib"]
+
+struct NonCopy;
+struct NeverCopy(NonCopy);
+
+impl !Copy for NeverCopy {}
+
+
+struct WithDrop;
+impl Drop for WithDrop { fn drop(&mut self) {} }
+
+impl !Copy for WithDrop {}
+
+
+struct Type;
+trait Trait {}
+extern {
+    type ExternType;
+}
+
+impl !Copy for &mut Type {}
+
+impl !Copy for dyn Trait {}
+
+impl !Copy for ExternType {}
diff --git a/src/test/ui/coherence/deep-bad-copy-reason.stderr b/src/test/ui/coherence/deep-bad-copy-reason.stderr
index 295538cee6096..168ee57263d2a 100644
--- a/src/test/ui/coherence/deep-bad-copy-reason.stderr
+++ b/src/test/ui/coherence/deep-bad-copy-reason.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/deep-bad-copy-reason.rs:33:15
+  --> $DIR/deep-bad-copy-reason.rs:33:24
    |
 LL | pub struct List<'tcx, T>(Interned<'tcx, ListS<T>>);
    |                          ------------------------ this field does not implement `Copy`
 ...
 LL | impl<'tcx, T> Copy for List<'tcx, T> {}
-   |               ^^^^
+   |                        ^^^^^^^^^^^^^
    |
 note: the `Copy` impl for `Interned<'tcx, ListS<T>>` requires that `OpaqueListContents: Sized`
   --> $DIR/deep-bad-copy-reason.rs:23:26
diff --git a/src/test/ui/opt-in-copy.stderr b/src/test/ui/opt-in-copy.stderr
index 0a275f1aa41d7..4461567df0a2a 100644
--- a/src/test/ui/opt-in-copy.stderr
+++ b/src/test/ui/opt-in-copy.stderr
@@ -1,20 +1,20 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/opt-in-copy.rs:7:6
+  --> $DIR/opt-in-copy.rs:7:15
    |
 LL |     but_i_cant: CantCopyThis,
    |     ------------------------ this field does not implement `Copy`
 ...
 LL | impl Copy for IWantToCopyThis {}
-   |      ^^^^
+   |               ^^^^^^^^^^^^^^^
 
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/opt-in-copy.rs:19:6
+  --> $DIR/opt-in-copy.rs:19:15
    |
 LL |     ButICant(CantCopyThisEither),
    |              ------------------ this field does not implement `Copy`
 ...
 LL | impl Copy for IWantToCopyThisToo {}
-   |      ^^^^
+   |               ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/E0204.stderr b/src/test/ui/span/E0204.stderr
index 2575848435206..0b2166eed7ead 100644
--- a/src/test/ui/span/E0204.stderr
+++ b/src/test/ui/span/E0204.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0204.rs:5:6
+  --> $DIR/E0204.rs:5:15
    |
 LL |     foo: Vec<u32>,
    |     ------------- this field does not implement `Copy`
 ...
 LL | impl Copy for Foo { }
-   |      ^^^^
+   |               ^^^
 
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:7:10
@@ -19,13 +19,13 @@ LL |     ty: &'a mut bool,
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0204.rs:17:6
+  --> $DIR/E0204.rs:17:15
    |
 LL |     Bar { x: Vec<u32> },
    |           ----------- this field does not implement `Copy`
 ...
 LL | impl Copy for EFoo { }
-   |      ^^^^
+   |               ^^^^
 
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:19:10
diff --git a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
index e0f405eedfa69..9e6f0d9ebbd27 100644
--- a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
+++ b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/missing-bound-in-manual-copy-impl-2.rs:16:9
+  --> $DIR/missing-bound-in-manual-copy-impl-2.rs:16:18
    |
 LL | struct Wrapper<T>(T);
    |                   - this field does not implement `Copy`
 ...
 LL | impl<S> Copy for Wrapper<OnlyCopyIfDisplay<S>> {}
-   |         ^^^^
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the `Copy` impl for `OnlyCopyIfDisplay<S>` requires that `S: std::fmt::Display`
   --> $DIR/missing-bound-in-manual-copy-impl-2.rs:4:19
diff --git a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
index 218988511dbc3..fe2d133c8aa74 100644
--- a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
+++ b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/missing-bound-in-manual-copy-impl.rs:6:9
+  --> $DIR/missing-bound-in-manual-copy-impl.rs:6:18
    |
 LL | struct Wrapper<T>(T);
    |                   - this field does not implement `Copy`
 LL |
 LL | impl<S> Copy for Wrapper<S> {}
-   |         ^^^^
+   |                  ^^^^^^^^^^
    |
 help: consider restricting type parameter `S`
    |
diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.stderr b/src/test/ui/traits/copy-impl-cannot-normalize.stderr
index afdad160919f9..68b95b42b3463 100644
--- a/src/test/ui/traits/copy-impl-cannot-normalize.stderr
+++ b/src/test/ui/traits/copy-impl-cannot-normalize.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `T: TraitFoo` is not satisfied
-  --> $DIR/copy-impl-cannot-normalize.rs:22:1
+  --> $DIR/copy-impl-cannot-normalize.rs:22:18
    |
 LL | impl<T> Copy for Foo<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T`
+   |                  ^^^^^^ the trait `TraitFoo` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr
index 8ecdafdde2045..53ee4dd2e5bdb 100644
--- a/src/test/ui/union/union-copy.stderr
+++ b/src/test/ui/union/union-copy.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/union-copy.rs:12:6
+  --> $DIR/union-copy.rs:12:15
    |
 LL |     a: std::mem::ManuallyDrop<String>
    |     --------------------------------- this field does not implement `Copy`
 ...
 LL | impl Copy for W {}
-   |      ^^^^
+   |               ^
    |
 note: the `Copy` impl for `ManuallyDrop<String>` requires that `String: Copy`
   --> $DIR/union-copy.rs:8:8