Skip to content

Commit ba0ecbd

Browse files
committed
forbid empty impls for types with incoherent impls
1 parent dc184b4 commit ba0ecbd

File tree

6 files changed

+228
-5
lines changed

6 files changed

+228
-5
lines changed

compiler/rustc_typeck/src/coherence/inherent_impls.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
122122
const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
123123
const INTO_DEFINING_CRATE: &str =
124124
"consider moving this inherent impl into the crate defining the type if possible";
125+
const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
126+
and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
125127
const ADD_ATTR: &str =
126128
"alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
127129

@@ -137,13 +139,28 @@ impl<'tcx> InherentCollect<'tcx> {
137139
return;
138140
}
139141

140-
if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
141-
let hir::ItemKind::Impl(hir::Impl { items, .. }) = item.kind else {
142+
if self.tcx.features().rustc_attrs {
143+
let hir::ItemKind::Impl(&hir::Impl { items, .. }) = item.kind else {
142144
bug!("expected `impl` item: {:?}", item);
143145
};
144146

145-
for item in items {
146-
if !self.tcx.has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
147+
if !self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
148+
struct_span_err!(
149+
self.tcx.sess,
150+
item.span,
151+
E0390,
152+
"cannot define inherent `impl` for a type outside of crate where the type is defined",
153+
)
154+
.help(INTO_DEFINING_CRATE)
155+
.span_help(item.span, ADD_ATTR_TO_TY)
156+
.emit();
157+
return;
158+
}
159+
160+
for impl_item in items {
161+
if !self
162+
.tcx
163+
.has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
147164
{
148165
struct_span_err!(
149166
self.tcx.sess,
@@ -152,7 +169,7 @@ impl<'tcx> InherentCollect<'tcx> {
152169
"cannot define inherent `impl` for a type outside of crate where the type is defined",
153170
)
154171
.help(INTO_DEFINING_CRATE)
155-
.span_help(item.span, ADD_ATTR)
172+
.span_help(impl_item.span, ADD_ATTR)
156173
.emit();
157174
return;
158175
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_has_incoherent_inherent_impls]
4+
pub struct StructWithAttr;
5+
pub struct StructNoAttr;
6+
7+
#[rustc_has_incoherent_inherent_impls]
8+
pub enum EnumWithAttr {}
9+
pub enum EnumNoAttr {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// aux-build:extern-crate.rs
2+
#![feature(rustc_attrs)]
3+
extern crate extern_crate;
4+
5+
impl extern_crate::StructWithAttr { //~ ERROR
6+
fn foo() {}
7+
}
8+
impl extern_crate::StructWithAttr {
9+
#[rustc_allow_incoherent_impl]
10+
fn bar() {}
11+
}
12+
impl extern_crate::StructNoAttr { //~ ERROR
13+
fn foo() {}
14+
}
15+
impl extern_crate::StructNoAttr { //~ ERROR
16+
#[rustc_allow_incoherent_impl]
17+
fn bar() {}
18+
}
19+
impl extern_crate::EnumWithAttr { //~ ERROR
20+
fn foo() {}
21+
}
22+
impl extern_crate::EnumWithAttr {
23+
#[rustc_allow_incoherent_impl]
24+
fn bar() {}
25+
}
26+
impl extern_crate::EnumNoAttr { //~ ERROR
27+
fn foo() {}
28+
}
29+
impl extern_crate::EnumNoAttr { //~ ERROR
30+
#[rustc_allow_incoherent_impl]
31+
fn bar() {}
32+
}
33+
34+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
2+
--> $DIR/needs-has-incoherent-impls.rs:5:1
3+
|
4+
LL | / impl extern_crate::StructWithAttr {
5+
LL | | fn foo() {}
6+
LL | | }
7+
| |_^
8+
|
9+
= help: consider moving this inherent impl into the crate defining the type if possible
10+
help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
11+
--> $DIR/needs-has-incoherent-impls.rs:6:5
12+
|
13+
LL | fn foo() {}
14+
| ^^^^^^^^^^^
15+
16+
error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
17+
--> $DIR/needs-has-incoherent-impls.rs:12:1
18+
|
19+
LL | / impl extern_crate::StructNoAttr {
20+
LL | | fn foo() {}
21+
LL | | }
22+
| |_^
23+
|
24+
= help: consider moving this inherent impl into the crate defining the type if possible
25+
help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
26+
--> $DIR/needs-has-incoherent-impls.rs:12:1
27+
|
28+
LL | / impl extern_crate::StructNoAttr {
29+
LL | | fn foo() {}
30+
LL | | }
31+
| |_^
32+
33+
error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
34+
--> $DIR/needs-has-incoherent-impls.rs:15:1
35+
|
36+
LL | / impl extern_crate::StructNoAttr {
37+
LL | | #[rustc_allow_incoherent_impl]
38+
LL | | fn bar() {}
39+
LL | | }
40+
| |_^
41+
|
42+
= help: consider moving this inherent impl into the crate defining the type if possible
43+
help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
44+
--> $DIR/needs-has-incoherent-impls.rs:15:1
45+
|
46+
LL | / impl extern_crate::StructNoAttr {
47+
LL | | #[rustc_allow_incoherent_impl]
48+
LL | | fn bar() {}
49+
LL | | }
50+
| |_^
51+
52+
error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
53+
--> $DIR/needs-has-incoherent-impls.rs:19:1
54+
|
55+
LL | / impl extern_crate::EnumWithAttr {
56+
LL | | fn foo() {}
57+
LL | | }
58+
| |_^
59+
|
60+
= help: consider moving this inherent impl into the crate defining the type if possible
61+
help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
62+
--> $DIR/needs-has-incoherent-impls.rs:20:5
63+
|
64+
LL | fn foo() {}
65+
| ^^^^^^^^^^^
66+
67+
error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
68+
--> $DIR/needs-has-incoherent-impls.rs:26:1
69+
|
70+
LL | / impl extern_crate::EnumNoAttr {
71+
LL | | fn foo() {}
72+
LL | | }
73+
| |_^
74+
|
75+
= help: consider moving this inherent impl into the crate defining the type if possible
76+
help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
77+
--> $DIR/needs-has-incoherent-impls.rs:26:1
78+
|
79+
LL | / impl extern_crate::EnumNoAttr {
80+
LL | | fn foo() {}
81+
LL | | }
82+
| |_^
83+
84+
error[E0390]: cannot define inherent `impl` for a type outside of crate where the type is defined
85+
--> $DIR/needs-has-incoherent-impls.rs:29:1
86+
|
87+
LL | / impl extern_crate::EnumNoAttr {
88+
LL | | #[rustc_allow_incoherent_impl]
89+
LL | | fn bar() {}
90+
LL | | }
91+
| |_^
92+
|
93+
= help: consider moving this inherent impl into the crate defining the type if possible
94+
help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
95+
--> $DIR/needs-has-incoherent-impls.rs:29:1
96+
|
97+
LL | / impl extern_crate::EnumNoAttr {
98+
LL | | #[rustc_allow_incoherent_impl]
99+
LL | | fn bar() {}
100+
LL | | }
101+
| |_^
102+
103+
error: aborting due to 6 previous errors
104+
105+
For more information about this error, try `rustc --explain E0390`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// aux-build:extern-crate.rs
2+
extern crate extern_crate;
3+
4+
impl extern_crate::StructWithAttr {} //~ ERROR
5+
6+
impl extern_crate::StructNoAttr {} //~ ERROR
7+
8+
impl extern_crate::EnumWithAttr {} //~ ERROR
9+
10+
impl extern_crate::EnumNoAttr {} //~ ERROR
11+
12+
impl f32 {} //~ ERROR
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
2+
--> $DIR/no-attr-empty-impl.rs:4:1
3+
|
4+
LL | impl extern_crate::StructWithAttr {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
6+
|
7+
= note: define and implement a trait or new type instead
8+
9+
error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
10+
--> $DIR/no-attr-empty-impl.rs:6:1
11+
|
12+
LL | impl extern_crate::StructNoAttr {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
14+
|
15+
= note: define and implement a trait or new type instead
16+
17+
error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
18+
--> $DIR/no-attr-empty-impl.rs:8:1
19+
|
20+
LL | impl extern_crate::EnumWithAttr {}
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
22+
|
23+
= note: define and implement a trait or new type instead
24+
25+
error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
26+
--> $DIR/no-attr-empty-impl.rs:10:1
27+
|
28+
LL | impl extern_crate::EnumNoAttr {}
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
30+
|
31+
= note: define and implement a trait or new type instead
32+
33+
error[E0390]: cannot define inherent `impl` for primitive types
34+
--> $DIR/no-attr-empty-impl.rs:12:6
35+
|
36+
LL | impl f32 {}
37+
| ^^^
38+
|
39+
= help: consider using an extension trait instead
40+
41+
error: aborting due to 5 previous errors
42+
43+
Some errors have detailed explanations: E0116, E0390.
44+
For more information about an error, try `rustc --explain E0116`.

0 commit comments

Comments
 (0)