You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
*const T has quite a few methods that seem like they don't need to require T: Sized #42847
error[E0277]: the trait bound `foo_t: std::marker::Sized` is not satisfied
--> src/main.rs:15:5
|
15 | std::ptr::null()
| ^^^^^^^^^^^^^^ `foo_t` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `foo_t`
= note: required by `std::ptr::null`
Do mind that the conclusion drawn in the last thread I linked seemed to be that null vtable pointers (even on raw pointers) are currently considered to be UB in rust.
(I'm not saying that you necessarily shouldn't; just pointing out. Maybe new facts and use cases may bring a new perspective)
Edit: wow, it just occurred to me what you're showing in that example. I never realized that rust had any unsized types that use thin pointers!
Unless there's a trait to distinguish between thin+unsized and fat+unsized pointers, we cannot relax the Sized bounds. In particular, trait object pointers *const dyn Trait must not have a null vtable (unless we have impl Trait for ! for all traits), and thus null() should not be defined for trait objects.
When the custom DST traits are included we could define
fnnull<T: ?Sized>() -> *constTwhereT::Meta:Default,{/* assemble a custom DST from { ptr = 0, meta = T::Meta::default() } */}
I can certainly see that a null vtable would be a bad thing, but I also feel that the complete inability to create a NULLor uninitialized extern type is going to be a real blocker to a lot of usage of extern types:
#![feature(extern_types)]extern{typefoo_t;fnfoo_init(f:*mutfoo_t);}fnmain(){letmut a = std::mem::uninitialized();unsafe{foo_init(&mut a)};}
error[E0277]: the trait bound `foo_t: std::marker::Sized` is not satisfied
--> src/main.rs:10:9
|
10 | let mut a = std::mem::uninitialized();
| ^^^^^ `foo_t` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `foo_t`
= note: all local variables must have a statically known size
Edit — that was a dumb example because of course a can't be on the stack, it's unsized. The real example of that would work:
#![feature(extern_types)]extern"C"{typefoo_t;fnfoo_init(f:*mut*mutfoo_t);}fnmain(){unsafe{letmut a = std::mem::uninitialized();foo_init(&mut a);}}
The corresponding equivalent with null still doesn't:
#![feature(extern_types)]extern"C"{typefoo_t;fnfoo_init(f:*mut*mutfoo_t);}fnmain(){unsafe{letmut a = std::ptr::null_mut();foo_init(&mut a);}}
error[E0277]: the trait bound `foo_t: std::marker::Sized` is not satisfied
--> src/main.rs:11:21
|
11 | let mut a = std::ptr::null_mut();
| ^^^^^^^^^^^^^^^^^^ `foo_t` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `foo_t`
= note: required by `std::ptr::null_mut`
We should add a private/unstable marker trait and use it to add a bound that's weaker than Sized.
It should be directly equivalent to T::Meta == (). The implementation can use unions and an assert that the size of the pointer matches that of a regular pointer (which it always would for this trait).
Is null and null_mut for extern types the only remaining thing tracked in this issue?
RFC 2580 (implementation PR: #81172) add public APIs for pointer metadata and a pub trait Thin = Pointee<Metadata = ()>;.
Building on top of that, I hoped that fixing this issue would be as simple as
-pub const fn null<T>() -> *const T {+pub const fn null<T: ?Sized + Thin>() -> *const T {-pub const fn null_mut<T>() -> *mut T {+pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
However this gives two kinds of errors when compiling libcore:
error[E0606]: casting `usize` as `*constT` is invalid
--> library/core/src/ptr/mod.rs:210:5
|
210 | 0as*constT
| ^^^^^^^^^^^^^
error[E0606]: casting `usize` as `*mutT` is invalid
--> library/core/src/ptr/mod.rs:228:5
|
228 | 0as*mutT
| ^^^^^^^^^^^
Possible fix: in compiler/rustc_typeck/src/check/cast.rs, in FnCtxt::pointer_kind, in the ty::Param case: if a Pointee<Metadata = ()> bound is in scope for that parameter return Ok(Some(PointerKind::Thin)). This might be similar to type_is_known_to_be_sized_modulo_regions which for type parameters presumably checks if a (possibly implicity) Sized bound is in scope.
error[E0271]:type mismatch resolving `<TasPointee>::Metadata == ()`
--> library/core/src/sync/atomic.rs:171:24
|
171 | AtomicPtr::new(crate::ptr::null_mut())
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
::: library/core/src/ptr/mod.rs:227:35
|
227 | pub const fn null_mut<T: ?Sized + Thin>() -> *mut T{
| ---- required by this bound in `ptr::null_mut`
|
= note:expected unit type `()`
found associated type `<TasPointee>::Metadata`
= help: consider constraining the associated type `<TasPointee>::Metadata` to `()`
= note:for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced>
Possible fix? “Somehow” teach the trait resolver that T: Sized implies T: Pointee<Metadata = ()>. Maybe in the compiler itself, as changing the library definition to trait Sized: Thin {} causes many instances of error[E0271]: type mismatch resolving `<Something as Pointee>::Metadata == ()` .
I hope we can do trait Sized: Thin {} in the library in addition to whatever compiler tricks are needed, as the supertrait is "morally correct" and good for documentation.
AtomicPtr specifically should probably have the same T: ?Sized + Thin bound, so the issue would go away there - but I agree with making trait Sized: Thin {}
Related: pointer::cast requires the generic parameter U to be Sized. Is this intentional? I would expect it to be a valid way to cast a pointer to a #[repr(transparent)] type to a pointer to its containing type or the other way around, same as an as cast or mem::transmute::<*const ReprTransparentType, *const InnerType>.
Reacted by Mads Marquart, dylni and Thomas M Kehrenberg
Activity
smmalis37 commentedon Jul 25, 2017
Adding to this, std::ptr::null & std::ptr::null_mut. Technically not methods on *const T but has these bounds too.
ExpHP commentedon Feb 21, 2018
All inherent methods and trait impls for
*const Tand*mut Tnow have aT: ?Sizedbound thanks to #44932 and #46094.Following the paper trail, it appears that there may be good reason that
std::ptr::{null,null_mut}do not supportT: ?Sized.shepmaster commentedon Apr 30, 2018
Should I open a new issue to argue about
std::ptr::null/std::ptr::null_mut? Seems wrong when used with extern types:ExpHP commentedon Apr 30, 2018
Do mind that the conclusion drawn in the last thread I linked seemed to be that null vtable pointers (even on raw pointers) are currently considered to be UB in rust.
(I'm not saying that you necessarily shouldn't; just pointing out. Maybe new facts and use cases may bring a new perspective)
Edit: wow, it just occurred to me what you're showing in that example. I never realized that rust had any unsized types that use thin pointers!
shepmaster commentedon May 5, 2018
I'll be that person and ping in @dtolnay, @eddyb, and @mikeyhew for some more discussion around my last comment
kennytm commentedon May 5, 2018
Unless there's a trait to distinguish between thin+unsized and fat+unsized pointers, we cannot relax the
Sizedbounds. In particular, trait object pointers*const dyn Traitmust not have a null vtable (unless we haveimpl Trait for !for all traits), and thusnull()should not be defined for trait objects.When the custom DST traits are included we could define
shepmaster commentedon May 5, 2018
I can certainly see that a null vtable would be a bad thing, but I also feel that the complete inability to create a
NULLor uninitializedextern type is going to be a real blocker to a lot of usage of extern types:Edit — that was a dumb example because of course
acan't be on the stack, it's unsized. The real example of that would work:The corresponding equivalent with
nullstill doesn't:dtolnay commentedon May 5, 2018
As a workaround for now you can get a null pointer to extern type through
as:eddyb commentedon Jul 31, 2018
We should add a private/unstable marker trait and use it to add a bound that's weaker than
Sized.It should be directly equivalent to
T::Meta == (). The implementation can use unions and an assert that the size of the pointer matches that of a regular pointer (which it always would for this trait).cc @retep998
SimonSapin commentedon Jan 18, 2021
Is
nullandnull_mutfor extern types the only remaining thing tracked in this issue?RFC 2580 (implementation PR: #81172) add public APIs for pointer metadata and a
pub trait Thin = Pointee<Metadata = ()>;.Building on top of that, I hoped that fixing this issue would be as simple as
However this gives two kinds of errors when compiling libcore:
Possible fix: in
compiler/rustc_typeck/src/check/cast.rs, inFnCtxt::pointer_kind, in thety::Paramcase: if aPointee<Metadata = ()>bound is in scope for that parameter returnOk(Some(PointerKind::Thin)). This might be similar totype_is_known_to_be_sized_modulo_regionswhich for type parameters presumably checks if a (possibly implicity)Sizedbound is in scope.Possible fix? “Somehow” teach the trait resolver that
T: SizedimpliesT: Pointee<Metadata = ()>. Maybe in the compiler itself, as changing the library definition totrait Sized: Thin {}causes many instances oferror[E0271]: type mismatch resolving `<Something as Pointee>::Metadata == ()`.Ericson2314 commentedon Jan 18, 2021
I hope we can do
trait Sized: Thin {}in the library in addition to whatever compiler tricks are needed, as the supertrait is "morally correct" and good for documentation.madsmtm commentedon Jun 15, 2021
AtomicPtrspecifically should probably have the sameT: ?Sized + Thinbound, so the issue would go away there - but I agree with makingtrait Sized: Thin {}Add `unstable_extern_types` feature
jplatte commentedon Jun 21, 2021
Related:
pointer::castrequires the generic parameterUto beSized. Is this intentional? I would expect it to be a valid way to cast a pointer to a#[repr(transparent)]type to a pointer to its containing type or the other way around, same as anascast ormem::transmute::<*const ReprTransparentType, *const InnerType>.Add `unstable_extern_types` feature
Add `unstable_extern_types` feature
Add `unstable_extern_types` feature
Add `unstable_extern_types` feature
Add `unstable_extern_types` feature
Add `unstable_extern_types` feature
Add `unstable_extern_types` feature
Add `unstable_extern_types` feature