Skip to content

Commit b3b68f1

Browse files
committed
Add an intrinsic for ptr::metadata
1 parent 7b06810 commit b3b68f1

File tree

32 files changed

+413
-59
lines changed

32 files changed

+413
-59
lines changed

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -622,22 +622,34 @@ fn codegen_stmt<'tcx>(
622622
Rvalue::UnaryOp(un_op, ref operand) => {
623623
let operand = codegen_operand(fx, operand);
624624
let layout = operand.layout();
625-
let val = operand.load_scalar(fx);
626625
let res = match un_op {
627-
UnOp::Not => match layout.ty.kind() {
628-
ty::Bool => {
629-
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
630-
CValue::by_val(res, layout)
626+
UnOp::Not => {
627+
let val = operand.load_scalar(fx);
628+
match layout.ty.kind() {
629+
ty::Bool => {
630+
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
631+
CValue::by_val(res, layout)
632+
}
633+
ty::Uint(_) | ty::Int(_) => {
634+
CValue::by_val(fx.bcx.ins().bnot(val), layout)
635+
}
636+
_ => unreachable!("un op Not for {:?}", layout.ty),
631637
}
632-
ty::Uint(_) | ty::Int(_) => {
633-
CValue::by_val(fx.bcx.ins().bnot(val), layout)
638+
}
639+
UnOp::Neg => {
640+
let val = operand.load_scalar(fx);
641+
match layout.ty.kind() {
642+
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
643+
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
644+
_ => unreachable!("un op Neg for {:?}", layout.ty),
634645
}
635-
_ => unreachable!("un op Not for {:?}", layout.ty),
636-
},
637-
UnOp::Neg => match layout.ty.kind() {
638-
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
639-
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
640-
_ => unreachable!("un op Neg for {:?}", layout.ty),
646+
}
647+
UnOp::PtrMetadata => match layout.abi {
648+
Abi::Scalar(_) => CValue::zst(dest_layout),
649+
Abi::ScalarPair(_, _) => {
650+
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
651+
}
652+
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
641653
},
642654
};
643655
lval.write_cvalue(fx, res);

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
@@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> {
9595
CValue(CValueInner::ByValPair(value, extra), layout)
9696
}
9797

98+
/// Create an instance of a ZST
99+
///
100+
/// The is represented by a dangling pointer of suitable alignment.
101+
pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
102+
assert!(layout.is_zst());
103+
CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout)
104+
}
105+
98106
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
99107
self.1
100108
}

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -617,19 +617,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
617617

618618
mir::Rvalue::UnaryOp(op, ref operand) => {
619619
let operand = self.codegen_operand(bx, operand);
620-
let lloperand = operand.immediate();
621620
let is_float = operand.layout.ty.is_floating_point();
622-
let llval = match op {
623-
mir::UnOp::Not => bx.not(lloperand),
621+
let (val, layout) = match op {
622+
mir::UnOp::Not => {
623+
let llval = bx.not(operand.immediate());
624+
(OperandValue::Immediate(llval), operand.layout)
625+
}
624626
mir::UnOp::Neg => {
625-
if is_float {
626-
bx.fneg(lloperand)
627+
let llval = if is_float {
628+
bx.fneg(operand.immediate())
629+
} else {
630+
bx.neg(operand.immediate())
631+
};
632+
(OperandValue::Immediate(llval), operand.layout)
633+
}
634+
mir::UnOp::PtrMetadata => {
635+
debug_assert!(operand.layout.ty.is_unsafe_ptr());
636+
let (_, meta) = operand.val.pointer_parts();
637+
assert_eq!(operand.layout.fields.count() > 1, meta.is_some());
638+
if let Some(meta) = meta {
639+
(OperandValue::Immediate(meta), operand.layout.field(self.cx, 1))
627640
} else {
628-
bx.neg(lloperand)
641+
(OperandValue::ZeroSized, bx.cx().layout_of(bx.tcx().types.unit))
629642
}
630643
}
631644
};
632-
OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout }
645+
debug_assert!(
646+
val.is_expected_variant_for_type(self.cx, layout),
647+
"Made wrong variant {val:?} for type {layout:?}",
648+
);
649+
OperandRef { val, layout }
633650
}
634651

635652
mir::Rvalue::Discriminant(ref place) => {
@@ -712,8 +729,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
712729
let values = op.val.immediates_or_place().left_or_else(|p| {
713730
bug!("Field {field_idx:?} is {p:?} making {layout:?}");
714731
});
715-
inputs.extend(values);
716732
let scalars = self.value_kind(op.layout).scalars().unwrap();
733+
debug_assert_eq!(values.len(), scalars.len());
734+
inputs.extend(values);
717735
input_scalars.extend(scalars);
718736
}
719737

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
722722
// (Do nothing on `None` provenance, that cannot store immutability anyway.)
723723
if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind()
724724
&& *mutbl == Mutability::Not
725-
&& val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable())
725+
&& val.to_scalar_and_meta()?.0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable())
726726
// That next check is expensive, that's why we have all the guards above.
727727
&& ty.is_freeze(*ecx.tcx, ecx.param_env)
728728
{

compiler/rustc_const_eval/src/interpret/cast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
206206
assert!(cast_to.ty.is_unsafe_ptr());
207207
// Handle casting any ptr to raw ptr (might be a fat ptr).
208208
if cast_to.size == src.layout.size {
209-
// Thin or fat pointer that just hast the ptr kind of target type changed.
209+
// Thin or fat pointer that just has the ptr kind of target type changed.
210210
return Ok(ImmTy::from_immediate(**src, cast_to));
211211
} else {
212212
// Casting the metadata away from a fat ptr.

compiler/rustc_const_eval/src/interpret/operand.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> {
4545
}
4646
}
4747

48-
impl<Prov: Provenance> Immediate<Prov> {
48+
impl<'tcx, Prov: Provenance> Immediate<Prov> {
4949
pub fn new_pointer_with_meta(
5050
ptr: Pointer<Option<Prov>>,
5151
meta: MemPlaceMeta<Prov>,
@@ -99,12 +99,12 @@ impl<Prov: Provenance> Immediate<Prov> {
9999
/// Returns the scalar from the first component and optionally the 2nd component as metadata.
100100
#[inline]
101101
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
102-
pub fn to_scalar_and_meta(self) -> (Scalar<Prov>, MemPlaceMeta<Prov>) {
103-
match self {
102+
pub fn to_scalar_and_meta(self) -> InterpResult<'tcx, (Scalar<Prov>, MemPlaceMeta<Prov>)> {
103+
Ok(match self {
104104
Immediate::ScalarPair(val1, val2) => (val1, MemPlaceMeta::Meta(val2)),
105105
Immediate::Scalar(val) => (val, MemPlaceMeta::None),
106-
Immediate::Uninit => bug!("Got uninit where a scalar or scalar pair was expected"),
107-
}
106+
Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
107+
})
108108
}
109109
}
110110

compiler/rustc_const_eval/src/interpret/operator.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use rustc_middle::{bug, span_bug};
77
use rustc_span::symbol::sym;
88
use rustc_target::abi::Abi;
99

10-
use super::{err_ub, throw_ub, throw_ub_custom, ImmTy, Immediate, InterpCx, Machine, PlaceTy};
10+
use super::{
11+
err_ub, throw_ub, throw_ub_custom, ImmTy, Immediate, InterpCx, Machine, MemPlaceMeta, PlaceTy,
12+
};
1113

1214
use crate::fluent_generated as fluent;
1315

@@ -479,11 +481,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
479481
use rustc_middle::mir::UnOp::*;
480482

481483
let layout = val.layout;
482-
let val = val.to_scalar();
483484
trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
484485

485486
match layout.ty.kind() {
486487
ty::Bool => {
488+
let val = val.to_scalar();
487489
let val = val.to_bool()?;
488490
let res = match un_op {
489491
Not => !val,
@@ -492,6 +494,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
492494
Ok((ImmTy::from_bool(res, *self.tcx), false))
493495
}
494496
ty::Float(fty) => {
497+
let val = val.to_scalar();
495498
// No NaN adjustment here, `-` is a bitwise operation!
496499
let res = match (un_op, fty) {
497500
(Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
@@ -500,8 +503,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
500503
};
501504
Ok((ImmTy::from_scalar(res, layout), false))
502505
}
503-
_ => {
504-
assert!(layout.ty.is_integral());
506+
_ if layout.ty.is_integral() => {
507+
let val = val.to_scalar();
505508
let val = val.to_bits(layout.size)?;
506509
let (res, overflow) = match un_op {
507510
Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate
@@ -516,9 +519,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
516519
let truncated = self.truncate(res, layout);
517520
(truncated, overflow || self.sign_extend(truncated, layout) != res)
518521
}
522+
_ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
519523
};
520524
Ok((ImmTy::from_uint(res, layout), overflow))
521525
}
526+
ty::RawPtr(..) => {
527+
assert_eq!(un_op, PtrMetadata);
528+
let (_, meta) = val.to_scalar_and_meta()?;
529+
Ok((
530+
match meta {
531+
MemPlaceMeta::Meta(scalar) => {
532+
let ty = un_op.ty(*self.tcx, val.layout.ty);
533+
let layout = self.layout_of(ty)?;
534+
ImmTy::from_scalar(scalar, layout)
535+
}
536+
MemPlaceMeta::None => {
537+
let unit_layout = self.layout_of(self.tcx.types.unit)?;
538+
ImmTy::uninit(unit_layout)
539+
}
540+
},
541+
false,
542+
))
543+
}
544+
_ => {
545+
bug!("Unexpected unary op argument {val:?}")
546+
}
522547
}
523548
}
524549

compiler/rustc_const_eval/src/interpret/place.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ where
419419
let pointee_type =
420420
val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type");
421421
let layout = self.layout_of(pointee_type)?;
422-
let (ptr, meta) = val.to_scalar_and_meta();
422+
let (ptr, meta) = val.to_scalar_and_meta()?;
423423

424424
// `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
425425
// we hence can't call `size_and_align_of` since that asserts more validity than we want.

compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11051105
ty::Int(..) | ty::Uint(..) | ty::Bool
11061106
);
11071107
}
1108+
UnOp::PtrMetadata => {
1109+
check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..));
1110+
}
11081111
}
11091112
}
11101113
Rvalue::ShallowInitBox(operand, _) => {

0 commit comments

Comments
 (0)