Skip to content

unimplement PointerLike for trait objects #134573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -912,11 +912,20 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_deny_explicit_impl,
AttributeType::Normal,
template!(List: "implement_via_object = (true|false)"),
template!(Word),
ErrorFollowing,
EncodeCrossCrate::No,
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
),
rustc_attr!(
rustc_do_not_implement_via_object,
AttributeType::Normal,
template!(Word),
ErrorFollowing,
EncodeCrossCrate::No,
"#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
(`impl Trait for dyn Trait`)"
),
rustc_attr!(
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes,
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_analysis/src/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
45 changes: 2 additions & 43 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/trait_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ pub struct TraitDef {

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

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

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::rustc_coinductive, ..]
| [sym::rustc_must_implement_one_of, ..]
| [sym::rustc_deny_explicit_impl, ..]
| [sym::rustc_do_not_implement_via_object, ..]
| [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1717,6 +1717,7 @@ symbols! {
rustc_diagnostic_macros,
rustc_dirty,
rustc_do_not_const_check,
rustc_do_not_implement_via_object,
rustc_doc_primitive,
rustc_driver,
rustc_dummy,
Expand Down
4 changes: 3 additions & 1 deletion library/core/src/future/async_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ pub trait AsyncDrop {
}

#[lang = "async_destruct"]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
trait AsyncDestruct {
type AsyncDestructor: Future<Output = ()>;
}
Expand Down
29 changes: 21 additions & 8 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
)]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[rustc_specialization_trait]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
#[rustc_coinductive]
pub trait Sized {
// Empty.
Expand Down Expand Up @@ -181,7 +183,9 @@ pub trait Sized {
/// [^1]: Formerly known as *object safe*.
#[unstable(feature = "unsize", issue = "18598")]
#[lang = "unsize"]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait Unsize<T: ?Sized> {
// Empty.
}
Expand Down Expand Up @@ -815,7 +819,9 @@ impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
)]
#[lang = "discriminant_kind"]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait DiscriminantKind {
/// The type of the discriminant, which must satisfy the trait
/// bounds required by `mem::Discriminant`.
Expand Down Expand Up @@ -956,7 +962,9 @@ marker_impls! {
#[unstable(feature = "const_destruct", issue = "133214")]
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
#[cfg_attr(not(bootstrap), const_trait)]
pub trait Destruct {}

Expand All @@ -967,19 +975,22 @@ pub trait Destruct {}
#[unstable(feature = "tuple_trait", issue = "none")]
#[lang = "tuple_trait"]
#[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait Tuple {}

/// A marker for pointer-like types.
///
/// All types that have the same size and alignment as a `usize` or
/// `*const ()` automatically implement this trait.
/// This trait can only be implemented for types that have the same size and alignment
/// as a `usize` or `*const ()`.
#[unstable(feature = "pointer_like_trait", issue = "none")]
#[lang = "pointer_like"]
#[diagnostic::on_unimplemented(
message = "`{Self}` needs to have the same ABI as a pointer",
label = "`{Self}` needs to be a pointer-like type"
)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait PointerLike {}

#[cfg(not(bootstrap))]
Expand Down Expand Up @@ -1068,7 +1079,9 @@ marker_impls! {
reason = "internal trait for implementing various traits for all function pointers"
)]
#[lang = "fn_ptr_trait"]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait FnPtr: Copy + Clone {
/// Returns the address of the function pointer.
#[lang = "fn_ptr_addr"]
Expand Down
4 changes: 3 additions & 1 deletion library/core/src/mem/transmutability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
/// `usize` is stable, but not portable.
#[unstable(feature = "transmutability", issue = "99571")]
#[lang = "transmute_trait"]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
#[rustc_coinductive]
pub unsafe trait TransmuteFrom<Src, const ASSUME: Assume = { Assume::NOTHING }>
where
Expand Down
4 changes: 3 additions & 1 deletion library/core/src/ptr/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ use crate::ptr::NonNull;
///
/// [`to_raw_parts`]: *const::to_raw_parts
#[lang = "pointee_trait"]
#[rustc_deny_explicit_impl(implement_via_object = false)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait Pointee {
/// The type for metadata in pointers and references to `Self`.
#[lang = "metadata_type"]
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/dyn-star/dyn-pointer-like.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Test that `dyn PointerLike` and `dyn* PointerLike` do not implement `PointerLike`.
// This used to ICE during codegen.

#![crate_type = "lib"]

#![feature(pointer_like_trait, dyn_star)]
#![feature(unsized_fn_params)]
#![expect(incomplete_features)]
#![expect(internal_features)]

use std::marker::PointerLike;

pub fn lol(x: dyn* PointerLike) {
foo(x); //~ ERROR `dyn* PointerLike` needs to have the same ABI as a pointer
}

pub fn uwu(x: dyn PointerLike) {
foo(x); //~ ERROR `dyn PointerLike` needs to have the same ABI as a pointer
}

fn foo<T: PointerLike + ?Sized>(x: T) {
let _: dyn* PointerLike = x;
}
39 changes: 39 additions & 0 deletions tests/ui/dyn-star/dyn-pointer-like.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
error[E0277]: `dyn* PointerLike` needs to have the same ABI as a pointer
--> $DIR/dyn-pointer-like.rs:14:9
|
LL | foo(x);
| --- ^ the trait `PointerLike` is not implemented for `dyn* PointerLike`
| |
| required by a bound introduced by this call
|
= note: the trait bound `dyn* PointerLike: PointerLike` is not satisfied
note: required by a bound in `foo`
--> $DIR/dyn-pointer-like.rs:21:11
|
LL | fn foo<T: PointerLike + ?Sized>(x: T) {
| ^^^^^^^^^^^ required by this bound in `foo`
help: consider borrowing here
|
LL | foo(&x);
| +
LL | foo(&mut x);
| ++++

error[E0277]: `dyn PointerLike` needs to have the same ABI as a pointer
--> $DIR/dyn-pointer-like.rs:18:9
|
LL | foo(x);
| --- ^ `dyn PointerLike` needs to be a pointer-like type
| |
| required by a bound introduced by this call
|
= help: the trait `PointerLike` is not implemented for `dyn PointerLike`
note: required by a bound in `foo`
--> $DIR/dyn-pointer-like.rs:21:11
|
LL | fn foo<T: PointerLike + ?Sized>(x: T) {
| ^^^^^^^^^^^ required by this bound in `foo`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
50 changes: 37 additions & 13 deletions tests/ui/traits/deny-builtin-object-impl.current.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
--> $DIR/deny-builtin-object-impl.rs:19:23
error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
--> $DIR/deny-builtin-object-impl.rs:20:1
|
LL | test_not_object::<dyn NotObject>();
| ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
LL | impl NotImplYesObject for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `NotImplYesObject` not allowed

error[E0277]: the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
--> $DIR/deny-builtin-object-impl.rs:37:32
|
LL | test_not_impl_not_object::<dyn NotImplNotObject>();
| ^^^^^^^^^^^^^^^^^^^^ the trait `NotImplNotObject` is not implemented for `dyn NotImplNotObject`
|
help: this trait has no implementations, consider adding one
--> $DIR/deny-builtin-object-impl.rs:12:1
|
LL | trait NotImplNotObject {}
| ^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `test_not_impl_not_object`
--> $DIR/deny-builtin-object-impl.rs:28:32
|
LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
| ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`

error[E0277]: the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
--> $DIR/deny-builtin-object-impl.rs:40:32
|
LL | test_yes_impl_not_object::<dyn YesImplNotObject>();
| ^^^^^^^^^^^^^^^^^^^^ the trait `YesImplNotObject` is not implemented for `dyn YesImplNotObject`
|
help: this trait has no implementations, consider adding one
--> $DIR/deny-builtin-object-impl.rs:11:1
--> $DIR/deny-builtin-object-impl.rs:15:1
|
LL | trait NotObject {}
| ^^^^^^^^^^^^^^^
note: required by a bound in `test_not_object`
--> $DIR/deny-builtin-object-impl.rs:15:23
LL | trait YesImplNotObject {}
| ^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `test_yes_impl_not_object`
--> $DIR/deny-builtin-object-impl.rs:30:32
|
LL | fn test_not_object<T: NotObject + ?Sized>() {}
| ^^^^^^^^^ required by this bound in `test_not_object`
LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
| ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`

error: aborting due to 1 previous error
error: aborting due to 3 previous errors

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