Skip to content

Commit 809cbb1

Browse files
committed
Add an intrinsic for ptr::metadata
1 parent fb89862 commit 809cbb1

File tree

25 files changed

+410
-43
lines changed

25 files changed

+410
-43
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,11 +2398,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
23982398
}
23992399
}
24002400
}
2401-
CastKind::Transmute => {
2401+
CastKind::PtrToMetadata | CastKind::Transmute => {
24022402
span_mirbug!(
24032403
self,
24042404
rvalue,
2405-
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
2405+
"Unexpected CastKind::{cast_kind:?}, which is not permitted in Analysis MIR",
24062406
);
24072407
}
24082408
}

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,17 @@ fn codegen_stmt<'tcx>(
698698
lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
699699
}
700700
}
701+
Rvalue::Cast(CastKind::PtrToMetadata, ref operand, _to_ty) => {
702+
let operand = codegen_operand(fx, operand);
703+
let meta = match operand.layout().abi {
704+
Abi::Scalar(_) => CValue::zst(dest_layout),
705+
Abi::ScalarPair(_, _) => {
706+
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
707+
}
708+
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
709+
};
710+
lval.write_cvalue(fx, meta);
711+
}
701712
Rvalue::Cast(
702713
CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
703714
ref operand,

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>(
100100
assert!(layout.is_sized(), "unsized const value");
101101

102102
if layout.is_zst() {
103-
return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
103+
return CValue::zst(layout);
104104
}
105105

106106
match const_val {

compiler/rustc_codegen_cranelift/src/value_and_place.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ impl<'tcx> CValue<'tcx> {
111111
CValue(inner, layout)
112112
}
113113

114+
/// Create an instance of a ZST
115+
///
116+
/// The is represented by a dangling pointer of suitable alignment.
117+
pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
118+
assert!(layout.is_zst());
119+
CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout)
120+
}
121+
114122
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
115123
self.1
116124
}

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
565565
};
566566
OperandValue::Immediate(newval)
567567
}
568+
mir::CastKind::PtrToMetadata => {
569+
match operand.val {
570+
OperandValue::Immediate(_) => OperandValue::ZeroSized,
571+
OperandValue::Pair(_, meta) => OperandValue::Immediate(meta),
572+
_ => bug!("Unexpected operand to `PtrToMetadata`: {operand:?}"),
573+
}
574+
}
568575
mir::CastKind::Transmute => {
569576
self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| {
570577
bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}");

compiler/rustc_const_eval/src/interpret/cast.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6464
self.write_immediate(*res, dest)?;
6565
}
6666

67+
CastKind::PtrToMetadata => {
68+
let src = self.read_immediate(src)?;
69+
let res = self.ptr_to_metadata(&src, cast_layout)?;
70+
self.write_immediate(*res, dest)?;
71+
}
72+
6773
CastKind::PointerCoercion(
6874
PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer,
6975
) => {
@@ -204,7 +210,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
204210
assert!(cast_to.ty.is_unsafe_ptr());
205211
// Handle casting any ptr to raw ptr (might be a fat ptr).
206212
if cast_to.size == src.layout.size {
207-
// Thin or fat pointer that just hast the ptr kind of target type changed.
213+
// Thin or fat pointer that just has the ptr kind of target type changed.
208214
return Ok(ImmTy::from_immediate(**src, cast_to));
209215
} else {
210216
// Casting the metadata away from a fat ptr.
@@ -225,6 +231,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
225231
}
226232
}
227233

234+
fn ptr_to_metadata(
235+
&self,
236+
src: &ImmTy<'tcx, M::Provenance>,
237+
cast_to: TyAndLayout<'tcx>,
238+
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
239+
assert!(src.layout.ty.is_unsafe_ptr());
240+
return Ok(match **src {
241+
Immediate::Scalar(_) => {
242+
assert!(cast_to.is_zst());
243+
ImmTy::uninit(cast_to)
244+
}
245+
Immediate::ScalarPair(_, meta) => ImmTy::from_scalar(meta, cast_to),
246+
Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
247+
});
248+
}
249+
228250
pub fn pointer_expose_provenance_cast(
229251
&mut self,
230252
src: &ImmTy<'tcx, M::Provenance>,

compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11351135
self.fail(location, "Can't cast {op_ty} into 'Ptr'");
11361136
}
11371137
}
1138+
CastKind::PtrToMetadata => {
1139+
if !op_ty.is_unsafe_ptr() {
1140+
self.fail(location, "Can't get ptr metadata from {op_ty}");
1141+
}
1142+
let pointee_ty = op_ty.builtin_deref(true).unwrap().ty;
1143+
1144+
// FIXME: Check metadata more generally
1145+
if pointee_ty.is_slice() {
1146+
if !self.mir_assign_valid_types(*target_type, self.tcx.types.usize) {
1147+
self.fail(location, "slice metadata must be usize");
1148+
}
1149+
} else if pointee_ty.is_sized(self.tcx, self.param_env) {
1150+
if *target_type != self.tcx.types.unit {
1151+
self.fail(location, "metadata for pointer-to-thin must be unit");
1152+
}
1153+
}
1154+
}
11381155
CastKind::FloatToFloat | CastKind::FloatToInt => {
11391156
if !op_ty.is_floating_point() || !target_type.is_numeric() {
11401157
self.fail(

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
129129
| sym::is_val_statically_known
130130
| sym::ptr_mask
131131
| sym::aggregate_raw_ptr
132+
| sym::ptr_metadata
132133
| sym::ub_checks
133134
| sym::fadd_algebraic
134135
| sym::fsub_algebraic
@@ -578,6 +579,7 @@ pub fn check_intrinsic_type(
578579
// This type check is not particularly useful, but the `where` bounds
579580
// on the definition in `core` do the heavy lifting for checking it.
580581
sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)),
582+
sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)),
581583

582584
sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
583585

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ impl<'tcx> Rvalue<'tcx> {
425425
| CastKind::IntToFloat
426426
| CastKind::FnPtrToPtr
427427
| CastKind::PtrToPtr
428+
| CastKind::PtrToMetadata
428429
| CastKind::PointerCoercion(_)
429430
| CastKind::PointerWithExposedProvenance
430431
| CastKind::DynStar

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,17 @@ pub enum CastKind {
13251325
IntToFloat,
13261326
PtrToPtr,
13271327
FnPtrToPtr,
1328+
/// Convert a raw pointer to an `impl Pointee<Metadata = M>` into `M`.
1329+
///
1330+
/// For example, this will give a `()` from `*const i32`, a `usize` from
1331+
/// `*mut [u8]`, or a vtable from a `*const dyn Foo`.
1332+
///
1333+
/// There's only one legal cast type based on the input type, but calculating
1334+
/// that type is expensive, and thus it's convenient for this to be a `Cast`
1335+
/// instead of an `UnOp`.
1336+
///
1337+
/// Allowed only in [`MirPhase::Runtime`]; Earlier it's an intrinsic.
1338+
PtrToMetadata,
13281339
/// Reinterpret the bits of the input as a different type.
13291340
///
13301341
/// MIR is well-formed if the input and output types have different sizes,

0 commit comments

Comments
 (0)