rust-lang/rust

`dyn Pointee` should be prohibited?

Opened this issue · 5 comments

kpreid commented

dyn Pointee is a weird type, because it (rightly!) implements Pointee for itself and not the erased concrete type:

#![feature(ptr_metadata)]
use std::ptr;
fn check<T: ?Sized + ptr::Pointee>(x: &T) {
    println!(
        "meta of {} is {}",
        std::any::type_name_of_val(x),
        std::any::type_name_of_val(&ptr::metadata(x)),
    );
}
fn main() {
    check(&100);
    check(&100 as &dyn ptr::Pointee<Metadata = ()>);
}
meta of i32 is ()
meta of dyn core::ptr::metadata::Pointee<Metadata = ()> is core::ptr::metadata::DynMetadata<dyn core::ptr::metadata::Pointee<Metadata = ()>>

This is internally consistent, but means that dyn Pointee is basically dyn EmptyTrait, despite what it claims.

Furthermore, there have been ICEs and unsoundness resulting from dyn Pointee or dyn HasPointeeAsSupertrait:

I therefore propose that, at least for the time being, the Pointee trait should be considered not dyn compatible. (As a precedent, consider that dyn Pointee<Metadata = ()> is basically the same meaning as dyn Sized, which is prohibited.) This restriction can be relaxed in the future if uses for it are found and the bugs are fixed.

@rustbot label +C-bug +A-dyn-trait +A-dyn-compatibility +T-lang
cc #81513

cc #148089, where dyn TraitWithThinAsSupertrait (where trait Thin = Pointee<Metadata = ()>;) causes codegen issues leading to a segfault in safe code.

Notably, from my debugging in that issue, maybe all #[rustc_do_not_implement_via_object] traits should be considered non-dyn-compatible? (though only some actually seem to cause issues)

It's probably easiest and can be relaxed later if all rustc_do_not_implement_via_object are not dyn compatible.

The only rustc_do_not_implement_via_object trait that I think should be dyn-compatible is Destruct, since I think we should allow something like const trait MyTrait: [const] Destruct to be dyn-compatible.

Other than Destruct, I don't see the point in allowing dyn for the other traits.

Actually, I don't know enough about MetaSized and PointeeSized to judge whether they should be dyn-compatible.

dyn MetaSized seems perfectly fine to continue allowing; it could even be useful (it can act as an empty trait. We could even maybe allow "upcasting" any dyn Trait to dyn MetaSized in the future).

dyn PointeeSized alone is currently rejected currently due to having no trait in the object type, since PointeeSized gets removed at an earlier stage of the compiler, and dyn PointeeSized + std::fmt::Debug (e.g.) is currently valid. I don't think this needs to be changed in relation to this issue, (though might need to be changed before PointeeSized could be stabilized).