diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index b68c73a46425e..e6092fc3787c6 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -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(()) + } } diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 1d6cc034dbac8..d584523aebe2f 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -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, +} diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 1e15446967b97..816fbac32f20d 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -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::()); @@ -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::()); @@ -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::()); + assert!(!pointer.mutable); + } + _ => unreachable!(), + } + + // Mutable pointer. + match const { Type::of::<*mut u64>() }.kind { + TypeKind::Pointer(pointer) => { + assert_eq!(pointer.pointee, TypeId::of::()); + assert!(pointer.mutable); + } + _ => unreachable!(), + } + + // Wide pointer. + match const { Type::of::<*const dyn Any>() }.kind { + TypeKind::Pointer(pointer) => { + assert_eq!(pointer.pointee, TypeId::of::()); + assert!(!pointer.mutable); + } + _ => unreachable!(), + } +}