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:
commit
25e6f5cda7
3 changed files with 82 additions and 5 deletions
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue