diff options
| author | Trevor Gross <t.gross35@gmail.com> | 2024-07-17 19:53:28 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-17 19:53:28 -0500 |
| commit | c36a39cd1ff78ec1336264d5a109ea96ae6642d4 (patch) | |
| tree | a6e73e45e7b81a3969ddeb498270f8e7d972ea70 | |
| parent | 3c4f820c5bf6627faf7c5e4bb1837ad47275b2b6 (diff) | |
| parent | f9c0d3370f04d08cda2da268a54bc543eb310fc7 (diff) | |
| download | rust-c36a39cd1ff78ec1336264d5a109ea96ae6642d4.tar.gz rust-c36a39cd1ff78ec1336264d5a109ea96ae6642d4.zip | |
Rollup merge of #127859 - RalfJung:ptr-dyn-metadata, r=scottmcm
ptr::metadata: avoid references to extern types References to `extern types` are somewhat dubious entities, since generally we say that references must be dereferenceable for their size as determined via `size_of_val`, but with `extern type` that is an ill-defined statement. I'd like to make Miri warn for such cases since it interacts poorly with Stacked Borrows. To avoid warnings people can't fix, this requires not using references to `extern type` in the standard library, and I think `DynMetadata` is the only currently remaining use. so this changes `DynMetadata` to use a NonNull raw pointer instead. Given that the alignment was 1, this shouldn't really change anything meaningful. I also updated a comment added by `@scottmcm` in https://github.com/rust-lang/rust/pull/125479, since I think the old comment is wrong. The `DynMetadata` type itself is not special, it is a normal aggregate. But computing field types for wide pointers (including references) is special.
| -rw-r--r-- | library/core/src/ptr/metadata.rs | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index eb86bf66206..06f205c0f26 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -5,6 +5,7 @@ use crate::hash::{Hash, Hasher}; use crate::intrinsics::aggregate_raw_ptr; use crate::intrinsics::ptr_metadata; use crate::marker::Freeze; +use crate::ptr::NonNull; /// Provides the pointer metadata type of any pointed-to type. /// @@ -153,7 +154,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>( /// compare equal (since identical vtables can be deduplicated within a codegen unit). #[lang = "dyn_metadata"] pub struct DynMetadata<Dyn: ?Sized> { - _vtable_ptr: &'static VTable, + _vtable_ptr: NonNull<VTable>, _phantom: crate::marker::PhantomData<Dyn>, } @@ -166,15 +167,18 @@ extern "C" { } impl<Dyn: ?Sized> DynMetadata<Dyn> { - /// One of the things that rustc_middle does with this being a lang item is - /// give it `FieldsShape::Primitive`, which means that as far as codegen can - /// tell, it *is* a reference, and thus doesn't have any fields. - /// That means we can't use field access, and have to transmute it instead. + /// When `DynMetadata` appears as the metadata field of a wide pointer, the rustc_middle layout + /// computation does magic and the resulting layout is *not* a `FieldsShape::Aggregate`, instead + /// it is a `FieldsShape::Primitive`. This means that the same type can have different layout + /// depending on whether it appears as the metadata field of a wide pointer or as a stand-alone + /// type, which understandably confuses codegen and leads to ICEs when trying to project to a + /// field of `DynMetadata`. To work around that issue, we use `transmute` instead of using a + /// field projection. #[inline] fn vtable_ptr(self) -> *const VTable { // SAFETY: this layout assumption is hard-coded into the compiler. // If it's somehow not a size match, the transmute will error. - unsafe { crate::mem::transmute::<Self, &'static VTable>(self) } + unsafe { crate::mem::transmute::<Self, *const VTable>(self) } } /// Returns the size of the type associated with this vtable. |
