From 809cbb1ecc22a780743b10258cf241bed14859aa Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 21 Apr 2024 16:11:01 -0700 Subject: [PATCH] Add an intrinsic for `ptr::metadata` --- compiler/rustc_borrowck/src/type_check/mod.rs | 4 +- compiler/rustc_codegen_cranelift/src/base.rs | 11 ++++ .../rustc_codegen_cranelift/src/constant.rs | 2 +- .../src/value_and_place.rs | 8 +++ compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 7 +++ .../rustc_const_eval/src/interpret/cast.rs | 24 ++++++- .../src/transform/validate.rs | 17 +++++ .../rustc_hir_analysis/src/check/intrinsic.rs | 2 + compiler/rustc_middle/src/mir/statement.rs | 1 + compiler/rustc_middle/src/mir/syntax.rs | 11 ++++ .../src/lower_intrinsics.rs | 18 ++++++ .../rustc_smir/src/rustc_smir/convert/mir.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/stable_mir/src/mir/body.rs | 1 + library/core/src/intrinsics.rs | 15 +++++ library/core/src/ptr/metadata.rs | 21 +++++-- library/core/tests/ptr.rs | 8 +++ tests/codegen/intrinsics/ptr_metadata.rs | 36 +++++++++++ ..._metadata.LowerIntrinsics.panic-abort.diff | 63 +++++++++++++++++++ ...metadata.LowerIntrinsics.panic-unwind.diff | 63 +++++++++++++++++++ tests/mir-opt/lower_intrinsics.rs | 9 +++ ...e_add_fat.PreCodegen.after.panic-abort.mir | 10 +-- ..._add_fat.PreCodegen.after.panic-unwind.mir | 10 +-- ...mut_range.PreCodegen.after.panic-abort.mir | 55 +++++++++++++--- ...ut_range.PreCodegen.after.panic-unwind.mir | 55 +++++++++++++--- 25 files changed, 410 insertions(+), 43 deletions(-) create mode 100644 tests/codegen/intrinsics/ptr_metadata.rs create mode 100644 tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff create mode 100644 tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 61fa84666744b..d6145ee49c67a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2398,11 +2398,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } - CastKind::Transmute => { + CastKind::PtrToMetadata | CastKind::Transmute => { span_mirbug!( self, rvalue, - "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", + "Unexpected CastKind::{cast_kind:?}, which is not permitted in Analysis MIR", ); } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index f428c4c7c0de0..bd2ab0c77fd2f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -698,6 +698,17 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, CValue::by_val(res, dest_layout)); } } + Rvalue::Cast(CastKind::PtrToMetadata, ref operand, _to_ty) => { + let operand = codegen_operand(fx, operand); + let meta = match operand.layout().abi { + Abi::Scalar(_) => CValue::zst(dest_layout), + Abi::ScalarPair(_, _) => { + CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout) + } + _ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"), + }; + lval.write_cvalue(fx, meta); + } Rvalue::Cast( CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), ref operand, diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index cb05c17ec2a88..51f64d8fca39e 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>( assert!(layout.is_sized(), "unsized const value"); if layout.is_zst() { - return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout); + return CValue::zst(layout); } match const_val { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 8d52fd9d7a8e4..85403be1fcde5 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -111,6 +111,14 @@ impl<'tcx> CValue<'tcx> { CValue(inner, layout) } + /// Create an instance of a ZST + /// + /// The is represented by a dangling pointer of suitable alignment. + pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> { + assert!(layout.is_zst()); + CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout) + } + pub(crate) fn layout(&self) -> TyAndLayout<'tcx> { self.1 } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7823d4c249a84..650f604fe0b45 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -565,6 +565,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; OperandValue::Immediate(newval) } + mir::CastKind::PtrToMetadata => { + match operand.val { + OperandValue::Immediate(_) => OperandValue::ZeroSized, + OperandValue::Pair(_, meta) => OperandValue::Immediate(meta), + _ => bug!("Unexpected operand to `PtrToMetadata`: {operand:?}"), + } + } mir::CastKind::Transmute => { self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| { bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}"); diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 9447d18fe8c93..7237629147be2 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -64,6 +64,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(*res, dest)?; } + CastKind::PtrToMetadata => { + let src = self.read_immediate(src)?; + let res = self.ptr_to_metadata(&src, cast_layout)?; + self.write_immediate(*res, dest)?; + } + CastKind::PointerCoercion( PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, ) => { @@ -204,7 +210,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(cast_to.ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). if cast_to.size == src.layout.size { - // Thin or fat pointer that just hast the ptr kind of target type changed. + // Thin or fat pointer that just has the ptr kind of target type changed. return Ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. @@ -225,6 +231,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + fn ptr_to_metadata( + &self, + src: &ImmTy<'tcx, M::Provenance>, + cast_to: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { + assert!(src.layout.ty.is_unsafe_ptr()); + return Ok(match **src { + Immediate::Scalar(_) => { + assert!(cast_to.is_zst()); + ImmTy::uninit(cast_to) + } + Immediate::ScalarPair(_, meta) => ImmTy::from_scalar(meta, cast_to), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), + }); + } + pub fn pointer_expose_provenance_cast( &mut self, src: &ImmTy<'tcx, M::Provenance>, diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index bf5592c828f1b..92c7fd2c1d57b 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1135,6 +1135,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, "Can't cast {op_ty} into 'Ptr'"); } } + CastKind::PtrToMetadata => { + if !op_ty.is_unsafe_ptr() { + self.fail(location, "Can't get ptr metadata from {op_ty}"); + } + let pointee_ty = op_ty.builtin_deref(true).unwrap().ty; + + // FIXME: Check metadata more generally + if pointee_ty.is_slice() { + if !self.mir_assign_valid_types(*target_type, self.tcx.types.usize) { + self.fail(location, "slice metadata must be usize"); + } + } else if pointee_ty.is_sized(self.tcx, self.param_env) { + if *target_type != self.tcx.types.unit { + self.fail(location, "metadata for pointer-to-thin must be unit"); + } + } + } CastKind::FloatToFloat | CastKind::FloatToInt => { if !op_ty.is_floating_point() || !target_type.is_numeric() { self.fail( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index fb4a76bf089f4..a5b6ea114b8cb 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -129,6 +129,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::is_val_statically_known | sym::ptr_mask | sym::aggregate_raw_ptr + | sym::ptr_metadata | sym::ub_checks | sym::fadd_algebraic | sym::fsub_algebraic @@ -578,6 +579,7 @@ pub fn check_intrinsic_type( // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)), + sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool), diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 069c8019cb2c8..d0e0f7030c070 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -425,6 +425,7 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::IntToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr + | CastKind::PtrToMetadata | CastKind::PointerCoercion(_) | CastKind::PointerWithExposedProvenance | CastKind::DynStar diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index db13bb9a3e8e4..b0821537519ac 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1325,6 +1325,17 @@ pub enum CastKind { IntToFloat, PtrToPtr, FnPtrToPtr, + /// Convert a raw pointer to an `impl Pointee` into `M`. + /// + /// For example, this will give a `()` from `*const i32`, a `usize` from + /// `*mut [u8]`, or a vtable from a `*const dyn Foo`. + /// + /// There's only one legal cast type based on the input type, but calculating + /// that type is expensive, and thus it's convenient for this to be a `Cast` + /// instead of an `UnOp`. + /// + /// Allowed only in [`MirPhase::Runtime`]; Earlier it's an intrinsic. + PtrToMetadata, /// Reinterpret the bits of the input as a different type. /// /// MIR is well-formed if the input and output types have different sizes, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index da63fcf23d9ee..478f73c7b367a 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -315,6 +315,24 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } + sym::ptr_metadata => { + let Ok([ptr]) = <[_; 1]>::try_from(std::mem::take(args)) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for ptr_metadata intrinsic", + ); + }; + let target = target.unwrap(); + let metadata_ty = generic_args.type_at(1); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::Cast(CastKind::PtrToMetadata, ptr.node, metadata_ty), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } _ => {} } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 7c0216211034c..376d177fc2aac 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -276,6 +276,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind { FloatToFloat => stable_mir::mir::CastKind::FloatToFloat, IntToFloat => stable_mir::mir::CastKind::IntToFloat, PtrToPtr => stable_mir::mir::CastKind::PtrToPtr, + PtrToMetadata => stable_mir::mir::CastKind::PtrToMetadata, FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr, Transmute => stable_mir::mir::CastKind::Transmute, } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f5eeb3d4ff1f6..9c8601e56b96c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1417,6 +1417,7 @@ symbols! { ptr_guaranteed_cmp, ptr_is_null, ptr_mask, + ptr_metadata, ptr_null, ptr_null_mut, ptr_offset_from, diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 6f666406c2210..ab657e18aec85 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -949,6 +949,7 @@ pub enum CastKind { FloatToFloat, IntToFloat, PtrToPtr, + PtrToMetadata, FnPtrToPtr, Transmute, } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 92f1bd274082b..6e3b7af7809ee 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2807,6 +2807,21 @@ impl AggregateRawPtr<*mut T> for *mut P { type Metadata =

::Metadata; } +/// Lowers in MIR to `Rvalue::Cast` with `CastKind::PtrToMetadata`. +/// +/// This is used to implement functions like `ptr::metadata`. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { + // To implement a fallback we'd have to assume the layout of the pointer, + // but the whole point of this intrinsic is that we shouldn't do that. + unreachable!() +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See . // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 1226c8e24194e..bc4a996e720eb 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -3,7 +3,7 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; #[cfg(not(bootstrap))] -use crate::intrinsics::aggregate_raw_ptr; +use crate::intrinsics::{aggregate_raw_ptr, ptr_metadata}; use crate::marker::Freeze; /// Provides the pointer metadata type of any pointed-to type. @@ -95,10 +95,17 @@ pub trait Thin = Pointee; #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn metadata(ptr: *const T) -> ::Metadata { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { const_ptr: ptr }.components.metadata } + #[cfg(bootstrap)] + { + // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T + // and PtrComponents have the same memory layouts. Only std can make this + // guarantee. + unsafe { PtrRepr { const_ptr: ptr }.components.metadata } + } + #[cfg(not(bootstrap))] + { + ptr_metadata(ptr) + } } /// Forms a (possibly-wide) raw pointer from a data pointer and metadata. @@ -153,6 +160,7 @@ pub const fn from_raw_parts_mut( } #[repr(C)] +#[cfg(bootstrap)] union PtrRepr { const_ptr: *const T, mut_ptr: *mut T, @@ -160,15 +168,18 @@ union PtrRepr { } #[repr(C)] +#[cfg(bootstrap)] struct PtrComponents { data_pointer: *const (), metadata: ::Metadata, } // Manual impl needed to avoid `T: Copy` bound. +#[cfg(bootstrap)] impl Copy for PtrComponents {} // Manual impl needed to avoid `T: Clone` bound. +#[cfg(bootstrap)] impl Clone for PtrComponents { fn clone(&self) -> Self { *self diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 7b55c2bf8a813..347c76cee64e8 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1171,3 +1171,11 @@ fn test_ptr_from_raw_parts_in_const() { assert_eq!(EMPTY_SLICE_PTR.addr(), 123); assert_eq!(EMPTY_SLICE_PTR.len(), 456); } + +#[test] +fn test_ptr_metadata_in_const() { + const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]); + const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]); + assert_eq!(ARRAY_META, ()); + assert_eq!(SLICE_META, 3); +} diff --git a/tests/codegen/intrinsics/ptr_metadata.rs b/tests/codegen/intrinsics/ptr_metadata.rs new file mode 100644 index 0000000000000..f4bf5a1f5f173 --- /dev/null +++ b/tests/codegen/intrinsics/ptr_metadata.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -O -C no-prepopulate-passes -Z inline-mir +//@ only-64bit (so I don't need to worry about usize) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::ptr_metadata; + +// CHECK-LABEL: @thin_metadata( +#[no_mangle] +pub fn thin_metadata(p: *const ()) { + // CHECK: start + // CHECK-NEXT: ret void + ptr_metadata(p) +} + +// CHECK-LABEL: @slice_metadata( +#[no_mangle] +pub fn slice_metadata(p: *const [u8]) -> usize { + // CHECK: start + // CHECK-NEXT: ret i64 %p.1 + ptr_metadata(p) +} + +// CHECK-LABEL: @dyn_byte_offset( +#[no_mangle] +pub unsafe fn dyn_byte_offset( + p: *const dyn std::fmt::Debug, + n: usize, +) -> *const dyn std::fmt::Debug { + // CHECK: %[[Q:.+]] = getelementptr inbounds i8, ptr %p.0, i64 %n + // CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0 + // CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1 + // CHECK: ret { ptr, ptr } %[[TEMP2]] + p.byte_add(n) +} diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff new file mode 100644 index 0000000000000..43c0964220bc7 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff @@ -0,0 +1,63 @@ +- // MIR for `get_metadata` before LowerIntrinsics ++ // MIR for `get_metadata` after LowerIntrinsics + + fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () { + debug a => _1; + debug b => _2; + debug c => _3; + let mut _0: (); + let _4: (); + let mut _5: *const i32; + let mut _7: *const [u8]; + let mut _9: *const dyn std::fmt::Debug; + scope 1 { + debug _unit => _4; + let _6: usize; + scope 2 { + debug _usize => _6; + let _8: std::ptr::DynMetadata; + scope 3 { + debug _vtable => _8; + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = ptr_metadata::(move _5) -> [return: bb1, unwind unreachable]; ++ _4 = move _5 as () (PtrToMetadata); ++ goto -> bb1; + } + + bb1: { + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + _7 = _2; +- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable]; ++ _6 = move _7 as usize (PtrToMetadata); ++ goto -> bb2; + } + + bb2: { + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = ptr_metadata::>(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = move _9 as std::ptr::DynMetadata (PtrToMetadata); ++ goto -> bb3; + } + + bb3: { + StorageDead(_9); + _0 = const (); + StorageDead(_8); + StorageDead(_6); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff new file mode 100644 index 0000000000000..43c0964220bc7 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff @@ -0,0 +1,63 @@ +- // MIR for `get_metadata` before LowerIntrinsics ++ // MIR for `get_metadata` after LowerIntrinsics + + fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () { + debug a => _1; + debug b => _2; + debug c => _3; + let mut _0: (); + let _4: (); + let mut _5: *const i32; + let mut _7: *const [u8]; + let mut _9: *const dyn std::fmt::Debug; + scope 1 { + debug _unit => _4; + let _6: usize; + scope 2 { + debug _usize => _6; + let _8: std::ptr::DynMetadata; + scope 3 { + debug _vtable => _8; + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = ptr_metadata::(move _5) -> [return: bb1, unwind unreachable]; ++ _4 = move _5 as () (PtrToMetadata); ++ goto -> bb1; + } + + bb1: { + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + _7 = _2; +- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable]; ++ _6 = move _7 as usize (PtrToMetadata); ++ goto -> bb2; + } + + bb2: { + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = ptr_metadata::>(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = move _9 as std::ptr::DynMetadata (PtrToMetadata); ++ goto -> bb3; + } + + bb3: { + StorageDead(_9); + _0 = const (); + StorageDead(_8); + StorageDead(_6); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 12e526ab0741d..120153e792d08 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -258,3 +258,12 @@ pub fn make_pointers(a: *const u8, b: *mut (), n: usize) { let _slice_const: *const [u16] = aggregate_raw_ptr(a, n); let _slice_mut: *mut [u64] = aggregate_raw_ptr(b, n); } + +// EMIT_MIR lower_intrinsics.get_metadata.LowerIntrinsics.diff +pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug) { + use std::intrinsics::ptr_metadata; + + let _unit = ptr_metadata(a); + let _usize = ptr_metadata(b); + let _vtable = ptr_metadata(c); +} diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index db0c84bd560fd..ab95ff33898fe 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: *const (); - let mut _7: usize; + let mut _6: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { - let mut _6: std::ptr::metadata::PtrRepr<[u32]>; } scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) { } @@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { StorageDead(_3); StorageLive(_5); _5 = _4 as *const () (PtrToPtr); - StorageLive(_7); StorageLive(_6); - _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 }; - _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize); + _6 = _1 as usize (PtrToMetadata); + _0 = *const [u32] from (_5, _6); StorageDead(_6); - _0 = *const [u32] from (_5, _7); - StorageDead(_7); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index db0c84bd560fd..ab95ff33898fe 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: *const (); - let mut _7: usize; + let mut _6: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { - let mut _6: std::ptr::metadata::PtrRepr<[u32]>; } scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) { } @@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { StorageDead(_3); StorageLive(_5); _5 = _4 as *const () (PtrToPtr); - StorageLive(_7); StorageLive(_6); - _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 }; - _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize); + _6 = _1 as usize (PtrToMetadata); + _0 = *const [u32] from (_5, _6); StorageDead(_6); - _0 = *const [u32] from (_5, _7); - StorageDead(_7); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index ef3f4a2172005..b8ce4850a09f7 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -4,20 +4,55 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _10: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let _6: usize; + let mut _7: *mut u32; + let mut _8: *mut u32; + scope 3 { + scope 6 (inlined std::ptr::mut_ptr::::as_mut_ptr) { + } + scope 7 (inlined std::ptr::mut_ptr::::add) { + } + scope 8 (inlined slice_from_raw_parts_mut::) { + let mut _9: *mut (); + scope 9 (inlined std::ptr::mut_ptr::::cast::<()>) { + } + scope 10 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + } + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_3); - _0 = &mut (*_4); + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = SubUnchecked(_4, _3); + StorageLive(_8); + StorageLive(_7); + _7 = _5 as *mut u32 (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + StorageLive(_9); + _9 = _8 as *mut () (PtrToPtr); + _10 = *mut [u32] from (_9, _6); + StorageDead(_9); + StorageDead(_8); + StorageDead(_6); + StorageDead(_5); + _0 = &mut (*_10); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 9e93a43ac725b..b8ce4850a09f7 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -4,20 +4,55 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _10: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let _6: usize; + let mut _7: *mut u32; + let mut _8: *mut u32; + scope 3 { + scope 6 (inlined std::ptr::mut_ptr::::as_mut_ptr) { + } + scope 7 (inlined std::ptr::mut_ptr::::add) { + } + scope 8 (inlined slice_from_raw_parts_mut::) { + let mut _9: *mut (); + scope 9 (inlined std::ptr::mut_ptr::::cast::<()>) { + } + scope 10 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + } + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_3); - _0 = &mut (*_4); + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = SubUnchecked(_4, _3); + StorageLive(_8); + StorageLive(_7); + _7 = _5 as *mut u32 (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + StorageLive(_9); + _9 = _8 as *mut () (PtrToPtr); + _10 = *mut [u32] from (_9, _6); + StorageDead(_9); + StorageDead(_8); + StorageDead(_6); + StorageDead(_5); + _0 = &mut (*_10); return; } }