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`).
This commit is contained in:
Lukas Markeffsky 2024-12-20 16:57:14 +01:00
parent 8a1f8039a7
commit 42c00cb647
13 changed files with 152 additions and 91 deletions

View file

@ -206,7 +206,9 @@ fn check_object_overlap<'tcx>(
// so this is valid.
} else {
let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id);
if supertrait_def_ids.any(|d| d == trait_def_id) {
if supertrait_def_ids
.any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
{
let span = tcx.def_span(impl_def_id);
return Err(struct_span_code_err!(
tcx.dcx(),

View file

@ -1261,49 +1261,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
no_dups.then_some(list)
});
let mut deny_explicit_impl = false;
let mut implement_via_object = true;
if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) {
deny_explicit_impl = true;
let mut seen_attr = false;
for meta in attr.meta_item_list().iter().flatten() {
if let Some(meta) = meta.meta_item()
&& meta.name_or_empty() == sym::implement_via_object
&& let Some(lit) = meta.name_value_literal()
{
if seen_attr {
tcx.dcx().span_err(meta.span, "duplicated `implement_via_object` meta item");
}
seen_attr = true;
match lit.symbol {
kw::True => {
implement_via_object = true;
}
kw::False => {
implement_via_object = false;
}
_ => {
tcx.dcx().span_err(
meta.span,
format!(
"unknown literal passed to `implement_via_object` attribute: {}",
lit.symbol
),
);
}
}
} else {
tcx.dcx().span_err(
meta.span(),
format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"),
);
}
}
if !seen_attr {
tcx.dcx().span_err(attr.span, "missing `implement_via_object` meta item");
}
}
let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
ty::TraitDef {
def_id: def_id.to_def_id(),