Rollup merge of #151119 - reflect-pointers, r=oli-obk

Support pointers in type reflection

Tracking issue: rust-lang/rust#146922

This PR adds support for inspecting pointers `*const T` and `*mut T` through type reflection. It does so by adding the new `Pointer` struct + variant:

```rust
pub struct Pointer {
    /// The type of the value being pointed to.
    pub ty: TypeId,
    /// Whether this pointer is mutable or not.
    pub mutable: bool,
}
```

This can be gathered using `Type::of`, for example:

```rust
match const { Type::of::<*const u8>() }.kind {
    TypeKind::Pointer(pointer) => {
        assert_eq!(pointer.ty, TypeId::of::<u8>());
        assert!(!pointer.mutable);
    }
    _ => unreachable!(),
}
```
This commit is contained in:
Jonathan Brouwer 2026-01-19 20:53:22 +01:00 committed by GitHub
commit 25e6f5cda7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 82 additions and 5 deletions

View file

@ -1,7 +1,6 @@
use rustc_abi::FieldIdx;
use rustc_ast::Mutability;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::{CtfeProvenance, Scalar};
use rustc_middle::span_bug;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Const, ScalarInt, Ty};
@ -9,7 +8,8 @@ use rustc_span::{Symbol, sym};
use crate::const_eval::CompileTimeMachine;
use crate::interpret::{
Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok,
CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable,
interp_ok,
};
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
@ -112,11 +112,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::RawPtr(ty, mutability) => {
let (variant, variant_place) = downcast(sym::Pointer)?;
let pointer_place =
self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_pointer_type_info(pointer_place, *ty, *mutability)?;
variant
}
ty::Adt(_, _)
| ty::Foreign(_)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::UnsafeBinder(..)
@ -312,4 +320,30 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
}
interp_ok(())
}
pub(crate) fn write_pointer_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
ty: Ty<'tcx>,
mutability: Mutability,
) -> InterpResult<'tcx> {
// Iterate over all fields of `type_info::Pointer`.
for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;
match field.name {
// Write the `TypeId` of the pointer's inner type to the `ty` field.
sym::pointee => self.write_type_id(ty, &field_place)?,
// Write the boolean representing the pointer's mutability to the `mutable` field.
sym::mutable => {
self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)?
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}
interp_ok(())
}
}

View file

@ -57,6 +57,8 @@ pub enum TypeKind {
Str(Str),
/// References.
Reference(Reference),
/// Pointers.
Pointer(Pointer),
/// FIXME(#146922): add all the common types
Other,
}
@ -146,3 +148,14 @@ pub struct Reference {
/// Whether this reference is mutable or not.
pub mutable: bool,
}
/// Compile-time type information about pointers.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Pointer {
/// The type of the value being pointed to.
pub pointee: TypeId,
/// Whether this pointer is mutable or not.
pub mutable: bool,
}

View file

@ -107,7 +107,7 @@ fn test_references() {
_ => unreachable!(),
}
// Mutable pointer.
// Mutable references.
match const { Type::of::<&mut u64>() }.kind {
TypeKind::Reference(reference) => {
assert_eq!(reference.pointee, TypeId::of::<u64>());
@ -116,7 +116,7 @@ fn test_references() {
_ => unreachable!(),
}
// Wide pointer.
// Wide references.
match const { Type::of::<&dyn Any>() }.kind {
TypeKind::Reference(reference) => {
assert_eq!(reference.pointee, TypeId::of::<dyn Any>());
@ -125,3 +125,33 @@ fn test_references() {
_ => unreachable!(),
}
}
#[test]
fn test_pointers() {
// Immutable pointer.
match const { Type::of::<*const u8>() }.kind {
TypeKind::Pointer(pointer) => {
assert_eq!(pointer.pointee, TypeId::of::<u8>());
assert!(!pointer.mutable);
}
_ => unreachable!(),
}
// Mutable pointer.
match const { Type::of::<*mut u64>() }.kind {
TypeKind::Pointer(pointer) => {
assert_eq!(pointer.pointee, TypeId::of::<u64>());
assert!(pointer.mutable);
}
_ => unreachable!(),
}
// Wide pointer.
match const { Type::of::<*const dyn Any>() }.kind {
TypeKind::Pointer(pointer) => {
assert_eq!(pointer.pointee, TypeId::of::<dyn Any>());
assert!(!pointer.mutable);
}
_ => unreachable!(),
}
}