Skip to content

Commit 42c00cb

Browse files
author
Lukas Markeffsky
committed
split up #[rustc_deny_explicit_impl] attribute
This commit splits the `#[rustc_deny_explicit_impl(implement_via_object = ...)]` attribute into two attributes `#[rustc_deny_explicit_impl]` and `#[rustc_do_not_implement_via_object]`. This allows us to have special traits that can have user-defined impls but do not have the automatic trait impl for trait objects (`impl Trait for dyn Trait`).
1 parent 8a1f803 commit 42c00cb

File tree

13 files changed

+152
-91
lines changed

13 files changed

+152
-91
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -912,11 +912,20 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
912912
rustc_attr!(
913913
rustc_deny_explicit_impl,
914914
AttributeType::Normal,
915-
template!(List: "implement_via_object = (true|false)"),
915+
template!(Word),
916916
ErrorFollowing,
917917
EncodeCrossCrate::No,
918918
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
919919
),
920+
rustc_attr!(
921+
rustc_do_not_implement_via_object,
922+
AttributeType::Normal,
923+
template!(Word),
924+
ErrorFollowing,
925+
EncodeCrossCrate::No,
926+
"#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
927+
(`impl Trait for dyn Trait`)"
928+
),
920929
rustc_attr!(
921930
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
922931
ErrorFollowing, EncodeCrossCrate::Yes,

compiler/rustc_hir_analysis/src/coherence/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ fn check_object_overlap<'tcx>(
206206
// so this is valid.
207207
} else {
208208
let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id);
209-
if supertrait_def_ids.any(|d| d == trait_def_id) {
209+
if supertrait_def_ids
210+
.any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
211+
{
210212
let span = tcx.def_span(impl_def_id);
211213
return Err(struct_span_code_err!(
212214
tcx.dcx(),

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,49 +1261,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
12611261
no_dups.then_some(list)
12621262
});
12631263

1264-
let mut deny_explicit_impl = false;
1265-
let mut implement_via_object = true;
1266-
if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) {
1267-
deny_explicit_impl = true;
1268-
let mut seen_attr = false;
1269-
for meta in attr.meta_item_list().iter().flatten() {
1270-
if let Some(meta) = meta.meta_item()
1271-
&& meta.name_or_empty() == sym::implement_via_object
1272-
&& let Some(lit) = meta.name_value_literal()
1273-
{
1274-
if seen_attr {
1275-
tcx.dcx().span_err(meta.span, "duplicated `implement_via_object` meta item");
1276-
}
1277-
seen_attr = true;
1278-
1279-
match lit.symbol {
1280-
kw::True => {
1281-
implement_via_object = true;
1282-
}
1283-
kw::False => {
1284-
implement_via_object = false;
1285-
}
1286-
_ => {
1287-
tcx.dcx().span_err(
1288-
meta.span,
1289-
format!(
1290-
"unknown literal passed to `implement_via_object` attribute: {}",
1291-
lit.symbol
1292-
),
1293-
);
1294-
}
1295-
}
1296-
} else {
1297-
tcx.dcx().span_err(
1298-
meta.span(),
1299-
format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"),
1300-
);
1301-
}
1302-
}
1303-
if !seen_attr {
1304-
tcx.dcx().span_err(attr.span, "missing `implement_via_object` meta item");
1305-
}
1306-
}
1264+
let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
1265+
let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
13071266

13081267
ty::TraitDef {
13091268
def_id: def_id.to_def_id(),

compiler/rustc_middle/src/ty/trait_def.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ pub struct TraitDef {
7070

7171
/// Whether to add a builtin `dyn Trait: Trait` implementation.
7272
/// This is enabled for all traits except ones marked with
73-
/// `#[rustc_deny_explicit_impl(implement_via_object = false)]`.
73+
/// `#[rustc_do_not_implement_via_object]`.
7474
pub implement_via_object: bool,
7575

7676
/// Whether a trait is fully built-in, and any implementation is disallowed.
7777
/// This only applies to built-in traits, and is marked via
78-
/// `#[rustc_deny_explicit_impl(implement_via_object = ...)]`.
78+
/// `#[rustc_deny_explicit_impl]`.
7979
pub deny_explicit_impl: bool,
8080
}
8181

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
186186
[sym::rustc_coinductive, ..]
187187
| [sym::rustc_must_implement_one_of, ..]
188188
| [sym::rustc_deny_explicit_impl, ..]
189+
| [sym::rustc_do_not_implement_via_object, ..]
189190
| [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
190191
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
191192
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,7 @@ symbols! {
17171717
rustc_diagnostic_macros,
17181718
rustc_dirty,
17191719
rustc_do_not_const_check,
1720+
rustc_do_not_implement_via_object,
17201721
rustc_doc_primitive,
17211722
rustc_driver,
17221723
rustc_dummy,

library/core/src/future/async_drop.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ pub trait AsyncDrop {
133133
}
134134

135135
#[lang = "async_destruct"]
136-
#[rustc_deny_explicit_impl(implement_via_object = false)]
136+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
137+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
138+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
137139
trait AsyncDestruct {
138140
type AsyncDestructor: Future<Output = ()>;
139141
}

library/core/src/marker.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
141141
)]
142142
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
143143
#[rustc_specialization_trait]
144-
#[rustc_deny_explicit_impl(implement_via_object = false)]
144+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
145+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
146+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
145147
#[rustc_coinductive]
146148
pub trait Sized {
147149
// Empty.
@@ -181,7 +183,9 @@ pub trait Sized {
181183
/// [^1]: Formerly known as *object safe*.
182184
#[unstable(feature = "unsize", issue = "18598")]
183185
#[lang = "unsize"]
184-
#[rustc_deny_explicit_impl(implement_via_object = false)]
186+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
187+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
188+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
185189
pub trait Unsize<T: ?Sized> {
186190
// Empty.
187191
}
@@ -815,7 +819,9 @@ impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
815819
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
816820
)]
817821
#[lang = "discriminant_kind"]
818-
#[rustc_deny_explicit_impl(implement_via_object = false)]
822+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
823+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
824+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
819825
pub trait DiscriminantKind {
820826
/// The type of the discriminant, which must satisfy the trait
821827
/// bounds required by `mem::Discriminant`.
@@ -956,7 +962,9 @@ marker_impls! {
956962
#[unstable(feature = "const_destruct", issue = "133214")]
957963
#[lang = "destruct"]
958964
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
959-
#[rustc_deny_explicit_impl(implement_via_object = false)]
965+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
966+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
967+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
960968
#[cfg_attr(not(bootstrap), const_trait)]
961969
pub trait Destruct {}
962970

@@ -967,7 +975,9 @@ pub trait Destruct {}
967975
#[unstable(feature = "tuple_trait", issue = "none")]
968976
#[lang = "tuple_trait"]
969977
#[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")]
970-
#[rustc_deny_explicit_impl(implement_via_object = false)]
978+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
979+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
980+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
971981
pub trait Tuple {}
972982

973983
/// A marker for pointer-like types.
@@ -1068,7 +1078,9 @@ marker_impls! {
10681078
reason = "internal trait for implementing various traits for all function pointers"
10691079
)]
10701080
#[lang = "fn_ptr_trait"]
1071-
#[rustc_deny_explicit_impl(implement_via_object = false)]
1081+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
1082+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
1083+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
10721084
pub trait FnPtr: Copy + Clone {
10731085
/// Returns the address of the function pointer.
10741086
#[lang = "fn_ptr_addr"]

library/core/src/mem/transmutability.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
8484
/// `usize` is stable, but not portable.
8585
#[unstable(feature = "transmutability", issue = "99571")]
8686
#[lang = "transmute_trait"]
87-
#[rustc_deny_explicit_impl(implement_via_object = false)]
87+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
88+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
89+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
8890
#[rustc_coinductive]
8991
pub unsafe trait TransmuteFrom<Src, const ASSUME: Assume = { Assume::NOTHING }>
9092
where

library/core/src/ptr/metadata.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ use crate::ptr::NonNull;
5353
///
5454
/// [`to_raw_parts`]: *const::to_raw_parts
5555
#[lang = "pointee_trait"]
56-
#[rustc_deny_explicit_impl(implement_via_object = false)]
56+
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
57+
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
58+
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
5759
pub trait Pointee {
5860
/// The type for metadata in pointers and references to `Self`.
5961
#[lang = "metadata_type"]
Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
1-
error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
2-
--> $DIR/deny-builtin-object-impl.rs:19:23
1+
error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
2+
--> $DIR/deny-builtin-object-impl.rs:20:1
33
|
4-
LL | test_not_object::<dyn NotObject>();
5-
| ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
4+
LL | impl NotImplYesObject for () {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `NotImplYesObject` not allowed
6+
7+
error[E0277]: the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
8+
--> $DIR/deny-builtin-object-impl.rs:37:32
9+
|
10+
LL | test_not_impl_not_object::<dyn NotImplNotObject>();
11+
| ^^^^^^^^^^^^^^^^^^^^ the trait `NotImplNotObject` is not implemented for `dyn NotImplNotObject`
12+
|
13+
help: this trait has no implementations, consider adding one
14+
--> $DIR/deny-builtin-object-impl.rs:12:1
15+
|
16+
LL | trait NotImplNotObject {}
17+
| ^^^^^^^^^^^^^^^^^^^^^^
18+
note: required by a bound in `test_not_impl_not_object`
19+
--> $DIR/deny-builtin-object-impl.rs:28:32
20+
|
21+
LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
22+
| ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
23+
24+
error[E0277]: the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
25+
--> $DIR/deny-builtin-object-impl.rs:40:32
26+
|
27+
LL | test_yes_impl_not_object::<dyn YesImplNotObject>();
28+
| ^^^^^^^^^^^^^^^^^^^^ the trait `YesImplNotObject` is not implemented for `dyn YesImplNotObject`
629
|
730
help: this trait has no implementations, consider adding one
8-
--> $DIR/deny-builtin-object-impl.rs:11:1
31+
--> $DIR/deny-builtin-object-impl.rs:15:1
932
|
10-
LL | trait NotObject {}
11-
| ^^^^^^^^^^^^^^^
12-
note: required by a bound in `test_not_object`
13-
--> $DIR/deny-builtin-object-impl.rs:15:23
33+
LL | trait YesImplNotObject {}
34+
| ^^^^^^^^^^^^^^^^^^^^^^
35+
note: required by a bound in `test_yes_impl_not_object`
36+
--> $DIR/deny-builtin-object-impl.rs:30:32
1437
|
15-
LL | fn test_not_object<T: NotObject + ?Sized>() {}
16-
| ^^^^^^^^^ required by this bound in `test_not_object`
38+
LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
39+
| ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
1740

18-
error: aborting due to 1 previous error
41+
error: aborting due to 3 previous errors
1942

20-
For more information about this error, try `rustc --explain E0277`.
43+
Some errors have detailed explanations: E0277, E0322.
44+
For more information about an error, try `rustc --explain E0277`.
Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
1-
error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
2-
--> $DIR/deny-builtin-object-impl.rs:19:23
1+
error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
2+
--> $DIR/deny-builtin-object-impl.rs:20:1
33
|
4-
LL | test_not_object::<dyn NotObject>();
5-
| ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
4+
LL | impl NotImplYesObject for () {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `NotImplYesObject` not allowed
6+
7+
error[E0277]: the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
8+
--> $DIR/deny-builtin-object-impl.rs:37:32
9+
|
10+
LL | test_not_impl_not_object::<dyn NotImplNotObject>();
11+
| ^^^^^^^^^^^^^^^^^^^^ the trait `NotImplNotObject` is not implemented for `dyn NotImplNotObject`
12+
|
13+
help: this trait has no implementations, consider adding one
14+
--> $DIR/deny-builtin-object-impl.rs:12:1
15+
|
16+
LL | trait NotImplNotObject {}
17+
| ^^^^^^^^^^^^^^^^^^^^^^
18+
note: required by a bound in `test_not_impl_not_object`
19+
--> $DIR/deny-builtin-object-impl.rs:28:32
20+
|
21+
LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
22+
| ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
23+
24+
error[E0277]: the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
25+
--> $DIR/deny-builtin-object-impl.rs:40:32
26+
|
27+
LL | test_yes_impl_not_object::<dyn YesImplNotObject>();
28+
| ^^^^^^^^^^^^^^^^^^^^ the trait `YesImplNotObject` is not implemented for `dyn YesImplNotObject`
629
|
730
help: this trait has no implementations, consider adding one
8-
--> $DIR/deny-builtin-object-impl.rs:11:1
31+
--> $DIR/deny-builtin-object-impl.rs:15:1
932
|
10-
LL | trait NotObject {}
11-
| ^^^^^^^^^^^^^^^
12-
note: required by a bound in `test_not_object`
13-
--> $DIR/deny-builtin-object-impl.rs:15:23
33+
LL | trait YesImplNotObject {}
34+
| ^^^^^^^^^^^^^^^^^^^^^^
35+
note: required by a bound in `test_yes_impl_not_object`
36+
--> $DIR/deny-builtin-object-impl.rs:30:32
1437
|
15-
LL | fn test_not_object<T: NotObject + ?Sized>() {}
16-
| ^^^^^^^^^ required by this bound in `test_not_object`
38+
LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
39+
| ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
1740

18-
error: aborting due to 1 previous error
41+
error: aborting due to 3 previous errors
1942

20-
For more information about this error, try `rustc --explain E0277`.
43+
Some errors have detailed explanations: E0277, E0322.
44+
For more information about an error, try `rustc --explain E0277`.

tests/ui/traits/deny-builtin-object-impl.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,41 @@
44

55
#![feature(rustc_attrs)]
66

7-
#[rustc_deny_explicit_impl(implement_via_object = true)]
8-
trait YesObject {}
7+
#[rustc_deny_explicit_impl]
8+
trait NotImplYesObject {}
99

10-
#[rustc_deny_explicit_impl(implement_via_object = false)]
11-
trait NotObject {}
10+
#[rustc_deny_explicit_impl]
11+
#[rustc_do_not_implement_via_object]
12+
trait NotImplNotObject {}
1213

13-
fn test_yes_object<T: YesObject + ?Sized>() {}
14+
#[rustc_do_not_implement_via_object]
15+
trait YesImplNotObject {}
1416

15-
fn test_not_object<T: NotObject + ?Sized>() {}
17+
#[rustc_do_not_implement_via_object]
18+
trait YesImplNotObject2 {}
19+
20+
impl NotImplYesObject for () {}
21+
//~^ ERROR explicit impls for the `NotImplYesObject` trait are not permitted
22+
23+
// If there is no automatic impl then we can add a manual impl:
24+
impl YesImplNotObject2 for dyn YesImplNotObject2 {}
25+
26+
fn test_not_impl_yes_object<T: NotImplYesObject + ?Sized>() {}
27+
28+
fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
29+
30+
fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
31+
32+
fn test_yes_impl_not_object2<T: YesImplNotObject2 + ?Sized>() {}
1633

1734
fn main() {
18-
test_yes_object::<dyn YesObject>();
19-
test_not_object::<dyn NotObject>();
20-
//~^ ERROR the trait bound `dyn NotObject: NotObject` is not satisfied
35+
test_not_impl_yes_object::<dyn NotImplYesObject>();
36+
37+
test_not_impl_not_object::<dyn NotImplNotObject>();
38+
//~^ ERROR the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
39+
40+
test_yes_impl_not_object::<dyn YesImplNotObject>();
41+
//~^ ERROR the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
42+
43+
test_yes_impl_not_object2::<dyn YesImplNotObject2>();
2144
}

0 commit comments

Comments
 (0)