about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2022-05-05 09:37:50 +0200
committerlcnr <rust@lcnr.de>2022-05-05 10:54:47 +0200
commitba0ecbdcd41879be9e5d3662c4c04c8e6c41f40b (patch)
tree35ec5230f6df04a597831d1368bb7f0ec0a5af7e
parentdc184b4e17639807617ac8aeeb51b4ee25817950 (diff)
downloadrust-ba0ecbdcd41879be9e5d3662c4c04c8e6c41f40b.tar.gz
rust-ba0ecbdcd41879be9e5d3662c4c04c8e6c41f40b.zip
forbid empty impls for types with incoherent impls
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs27
-rw-r--r--src/test/ui/incoherent-inherent-impls/auxiliary/extern-crate.rs9
-rw-r--r--src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.rs34
-rw-r--r--src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr105
-rw-r--r--src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.rs14
-rw-r--r--src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr44
6 files changed, 228 insertions, 5 deletions
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 8c2e91ab8f1..d50ac725710 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -122,6 +122,8 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
 const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
 const INTO_DEFINING_CRATE: &str =
     "consider moving this inherent impl into the crate defining the type if possible";
+const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
+     and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
 const ADD_ATTR: &str =
     "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
 
@@ -137,13 +139,28 @@ impl<'tcx> InherentCollect<'tcx> {
             return;
         }
 
-        if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
-            let hir::ItemKind::Impl(hir::Impl { items, .. }) = item.kind else {
+        if self.tcx.features().rustc_attrs {
+            let hir::ItemKind::Impl(&hir::Impl { items, .. }) = item.kind else {
                 bug!("expected `impl` item: {:?}", item);
             };
 
-            for item in items {
-                if !self.tcx.has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+            if !self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
+                struct_span_err!(
+                    self.tcx.sess,
+                    item.span,
+                    E0390,
+                    "cannot define inherent `impl` for a type outside of crate where the type is defined",
+                )
+                .help(INTO_DEFINING_CRATE)
+                .span_help(item.span, ADD_ATTR_TO_TY)
+                .emit();
+                return;
+            }
+
+            for impl_item in items {
+                if !self
+                    .tcx
+                    .has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
                 {
                     struct_span_err!(
                         self.tcx.sess,
@@ -152,7 +169,7 @@ impl<'tcx> InherentCollect<'tcx> {
                         "cannot define inherent `impl` for a type outside of crate where the type is defined",
                     )
                     .help(INTO_DEFINING_CRATE)
-                    .span_help(item.span, ADD_ATTR)
+                    .span_help(impl_item.span, ADD_ATTR)
                     .emit();
                     return;
                 }
diff --git a/src/test/ui/incoherent-inherent-impls/auxiliary/extern-crate.rs b/src/test/ui/incoherent-inherent-impls/auxiliary/extern-crate.rs
new file mode 100644
index 00000000000..22f0d912c8f
--- /dev/null
+++ b/src/test/ui/incoherent-inherent-impls/auxiliary/extern-crate.rs
@@ -0,0 +1,9 @@
+#![feature(rustc_attrs)]
+
+#[rustc_has_incoherent_inherent_impls]
+pub struct StructWithAttr;
+pub struct StructNoAttr;
+
+#[rustc_has_incoherent_inherent_impls]
+pub enum EnumWithAttr {}
+pub enum EnumNoAttr {}
diff --git a/src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.rs b/src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.rs
new file mode 100644
index 00000000000..ce5200a5008
--- /dev/null
+++ b/src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.rs
@@ -0,0 +1,34 @@
+// aux-build:extern-crate.rs
+#![feature(rustc_attrs)]
+extern crate extern_crate;
+
+impl extern_crate::StructWithAttr { //~ ERROR
+    fn foo() {}
+}
+impl extern_crate::StructWithAttr {
+    #[rustc_allow_incoherent_impl]
+    fn bar() {}
+}
+impl extern_crate::StructNoAttr { //~ ERROR
+    fn foo() {}
+}
+impl extern_crate::StructNoAttr { //~ ERROR
+    #[rustc_allow_incoherent_impl]
+    fn bar() {}
+}
+impl extern_crate::EnumWithAttr { //~ ERROR
+    fn foo() {}
+}
+impl extern_crate::EnumWithAttr {
+    #[rustc_allow_incoherent_impl]
+    fn bar() {}
+}
+impl extern_crate::EnumNoAttr { //~ ERROR
+    fn foo() {}
+}
+impl extern_crate::EnumNoAttr { //~ ERROR
+    #[rustc_allow_incoherent_impl]
+    fn bar() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr b/src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr
new file mode 100644
index 00000000000..1b0cadc2c28
--- /dev/null
+++ b/src/test/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr
@@ -0,0 +1,105 @@
+error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
+  --> $DIR/needs-has-incoherent-impls.rs:5:1
+   |
+LL | / impl extern_crate::StructWithAttr {
+LL | |     fn foo() {}
+LL | | }
+   | |_^
+   |
+   = help: consider moving this inherent impl into the crate defining the type if possible
+help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/needs-has-incoherent-impls.rs:6:5
+   |
+LL |     fn foo() {}
+   |     ^^^^^^^^^^^
+
+error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
+  --> $DIR/needs-has-incoherent-impls.rs:12:1
+   |
+LL | / impl extern_crate::StructNoAttr {
+LL | |     fn foo() {}
+LL | | }
+   | |_^
+   |
+   = help: consider moving this inherent impl into the crate defining the type if possible
+help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/needs-has-incoherent-impls.rs:12:1
+   |
+LL | / impl extern_crate::StructNoAttr {
+LL | |     fn foo() {}
+LL | | }
+   | |_^
+
+error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
+  --> $DIR/needs-has-incoherent-impls.rs:15:1
+   |
+LL | / impl extern_crate::StructNoAttr {
+LL | |     #[rustc_allow_incoherent_impl]
+LL | |     fn bar() {}
+LL | | }
+   | |_^
+   |
+   = help: consider moving this inherent impl into the crate defining the type if possible
+help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/needs-has-incoherent-impls.rs:15:1
+   |
+LL | / impl extern_crate::StructNoAttr {
+LL | |     #[rustc_allow_incoherent_impl]
+LL | |     fn bar() {}
+LL | | }
+   | |_^
+
+error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
+  --> $DIR/needs-has-incoherent-impls.rs:19:1
+   |
+LL | / impl extern_crate::EnumWithAttr {
+LL | |     fn foo() {}
+LL | | }
+   | |_^
+   |
+   = help: consider moving this inherent impl into the crate defining the type if possible
+help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/needs-has-incoherent-impls.rs:20:5
+   |
+LL |     fn foo() {}
+   |     ^^^^^^^^^^^
+
+error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
+  --> $DIR/needs-has-incoherent-impls.rs:26:1
+   |
+LL | / impl extern_crate::EnumNoAttr {
+LL | |     fn foo() {}
+LL | | }
+   | |_^
+   |
+   = help: consider moving this inherent impl into the crate defining the type if possible
+help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/needs-has-incoherent-impls.rs:26:1
+   |
+LL | / impl extern_crate::EnumNoAttr {
+LL | |     fn foo() {}
+LL | | }
+   | |_^
+
+error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
+  --> $DIR/needs-has-incoherent-impls.rs:29:1
+   |
+LL | / impl extern_crate::EnumNoAttr {
+LL | |     #[rustc_allow_incoherent_impl]
+LL | |     fn bar() {}
+LL | | }
+   | |_^
+   |
+   = help: consider moving this inherent impl into the crate defining the type if possible
+help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/needs-has-incoherent-impls.rs:29:1
+   |
+LL | / impl extern_crate::EnumNoAttr {
+LL | |     #[rustc_allow_incoherent_impl]
+LL | |     fn bar() {}
+LL | | }
+   | |_^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0390`.
diff --git a/src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.rs b/src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.rs
new file mode 100644
index 00000000000..6d11a7b8938
--- /dev/null
+++ b/src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.rs
@@ -0,0 +1,14 @@
+// aux-build:extern-crate.rs
+extern crate extern_crate;
+
+impl extern_crate::StructWithAttr {} //~ ERROR
+
+impl extern_crate::StructNoAttr {} //~ ERROR
+
+impl extern_crate::EnumWithAttr {} //~ ERROR
+
+impl extern_crate::EnumNoAttr {} //~ ERROR
+
+impl f32 {} //~ ERROR
+
+fn main() {}
diff --git a/src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr b/src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr
new file mode 100644
index 00000000000..b7fca9e9816
--- /dev/null
+++ b/src/test/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr
@@ -0,0 +1,44 @@
+error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
+  --> $DIR/no-attr-empty-impl.rs:4:1
+   |
+LL | impl extern_crate::StructWithAttr {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
+  --> $DIR/no-attr-empty-impl.rs:6:1
+   |
+LL | impl extern_crate::StructNoAttr {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
+  --> $DIR/no-attr-empty-impl.rs:8:1
+   |
+LL | impl extern_crate::EnumWithAttr {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
+  --> $DIR/no-attr-empty-impl.rs:10:1
+   |
+LL | impl extern_crate::EnumNoAttr {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0390]: cannot define inherent `impl` for primitive types
+  --> $DIR/no-attr-empty-impl.rs:12:6
+   |
+LL | impl f32 {}
+   |      ^^^
+   |
+   = help: consider using an extension trait instead
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0116, E0390.
+For more information about an error, try `rustc --explain E0116`.