Skip to content

Commit b26cd8c

Browse files
authored
Rollup merge of rust-lang#62946 - RalfJung:miri_type_dispatch_first, r=oli-obk
Miri: dispatch first on the type Based on the fact that Miri now always has intptrcast available, we can change binops and casts to first check the type of the source operand and then decide based on that what to do, instead of considering the value (pointer vs bits) first.
2 parents e3976ff + d7b9bbf commit b26cd8c

16 files changed

+153
-159
lines changed

src/librustc/ty/sty.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,12 @@ impl<'tcx> TyS<'tcx> {
18631863
}
18641864
}
18651865

1866+
/// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
1867+
#[inline]
1868+
pub fn is_any_ptr(&self) -> bool {
1869+
self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr()
1870+
}
1871+
18661872
/// Returns `true` if this type is an `Arc<T>`.
18671873
#[inline]
18681874
pub fn is_arc(&self) -> bool {

src/librustc_mir/const_eval.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ use rustc_data_structures::fx::FxHashMap;
2020
use syntax::source_map::{Span, DUMMY_SP};
2121

2222
use crate::interpret::{self,
23-
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar,
23+
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
2424
RawConst, ConstValue,
2525
InterpResult, InterpErrorInfo, InterpError, GlobalId, InterpCx, StackPopCleanup,
26-
Allocation, AllocId, MemoryKind,
26+
Allocation, AllocId, MemoryKind, Memory,
2727
snapshot, RefTracking, intern_const_alloc_recursive,
2828
};
2929

@@ -397,7 +397,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
397397
)
398398
}
399399

400-
fn ptr_op(
400+
fn ptr_to_int(
401+
_mem: &Memory<'mir, 'tcx, Self>,
402+
_ptr: Pointer,
403+
) -> InterpResult<'tcx, u64> {
404+
Err(
405+
ConstEvalError::NeedsRfc("pointer-to-integer cast".to_string()).into(),
406+
)
407+
}
408+
409+
fn binary_ptr_op(
401410
_ecx: &InterpCx<'mir, 'tcx, Self>,
402411
_bin_op: mir::BinOp,
403412
_left: ImmTy<'tcx>,

src/librustc_mir/interpret/cast.rs

+65-91
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,13 @@ use syntax::symbol::sym;
77
use rustc_apfloat::ieee::{Single, Double};
88
use rustc_apfloat::{Float, FloatConvert};
99
use rustc::mir::interpret::{
10-
Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
10+
Scalar, InterpResult, PointerArithmetic, InterpError,
1111
};
1212
use rustc::mir::CastKind;
1313

14-
use super::{InterpCx, Machine, PlaceTy, OpTy, Immediate, FnVal};
14+
use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal};
1515

1616
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
17-
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
18-
match ty.sty {
19-
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
20-
ty::Ref(_, ty, _) => !self.type_is_sized(ty),
21-
ty::Adt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
22-
_ => false,
23-
}
24-
}
25-
2617
pub fn cast(
2718
&mut self,
2819
src: OpTy<'tcx, M::PointerTag>,
@@ -37,40 +28,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3728

3829
Misc | Pointer(PointerCast::MutToConstPointer) => {
3930
let src = self.read_immediate(src)?;
40-
41-
if self.type_is_fat_ptr(src.layout.ty) {
42-
match (*src, self.type_is_fat_ptr(dest.layout.ty)) {
43-
// pointers to extern types
44-
(Immediate::Scalar(_),_) |
45-
// slices and trait objects to other slices/trait objects
46-
(Immediate::ScalarPair(..), true) => {
47-
// No change to immediate
48-
self.write_immediate(*src, dest)?;
49-
}
50-
// slices and trait objects to thin pointers (dropping the metadata)
51-
(Immediate::ScalarPair(data, _), false) => {
52-
self.write_scalar(data, dest)?;
53-
}
54-
}
55-
} else {
56-
match src.layout.variants {
57-
layout::Variants::Single { index } => {
58-
if let Some(discr) =
59-
src.layout.ty.discriminant_for_variant(*self.tcx, index)
60-
{
61-
// Cast from a univariant enum
62-
assert!(src.layout.is_zst());
63-
return self.write_scalar(
64-
Scalar::from_uint(discr.val, dest.layout.size),
65-
dest);
66-
}
67-
}
68-
layout::Variants::Multiple { .. } => {},
69-
}
70-
71-
let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
72-
self.write_scalar(dest_val, dest)?;
73-
}
31+
let res = self.cast_immediate(src, dest.layout)?;
32+
self.write_immediate(res, dest)?;
7433
}
7534

7635
Pointer(PointerCast::ReifyFnPointer) => {
@@ -126,36 +85,76 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
12685
Ok(())
12786
}
12887

129-
fn cast_scalar(
88+
fn cast_immediate(
13089
&self,
131-
val: Scalar<M::PointerTag>,
132-
src_layout: TyLayout<'tcx>,
90+
src: ImmTy<'tcx, M::PointerTag>,
13391
dest_layout: TyLayout<'tcx>,
134-
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
92+
) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
13593
use rustc::ty::TyKind::*;
136-
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
94+
trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty);
13795

138-
match src_layout.ty.sty {
96+
match src.layout.ty.sty {
13997
// Floating point
140-
Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
141-
Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
142-
// Integer(-like), including fn ptr casts and casts from enums that
143-
// are represented as integers (this excludes univariant enums, which
144-
// are handled in `cast` directly).
145-
_ => {
98+
Float(FloatTy::F32) =>
99+
return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty)?.into()),
100+
Float(FloatTy::F64) =>
101+
return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty)?.into()),
102+
// The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
103+
// are represented as integers.
104+
_ =>
146105
assert!(
147-
src_layout.ty.is_bool() || src_layout.ty.is_char() ||
148-
src_layout.ty.is_enum() || src_layout.ty.is_integral() ||
149-
src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr() ||
150-
src_layout.ty.is_region_ptr(),
151-
"Unexpected cast from type {:?}", src_layout.ty
152-
);
153-
match val.to_bits_or_ptr(src_layout.size, self) {
154-
Err(ptr) => self.cast_from_ptr(ptr, src_layout, dest_layout),
155-
Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
106+
src.layout.ty.is_bool() || src.layout.ty.is_char() ||
107+
src.layout.ty.is_enum() || src.layout.ty.is_integral() ||
108+
src.layout.ty.is_any_ptr(),
109+
"Unexpected cast from type {:?}", src.layout.ty
110+
)
111+
}
112+
113+
// Handle cast from a univariant (ZST) enum.
114+
match src.layout.variants {
115+
layout::Variants::Single { index } => {
116+
if let Some(discr) =
117+
src.layout.ty.discriminant_for_variant(*self.tcx, index)
118+
{
119+
assert!(src.layout.is_zst());
120+
return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
156121
}
157122
}
123+
layout::Variants::Multiple { .. } => {},
124+
}
125+
126+
// Handle casting the metadata away from a fat pointer.
127+
if src.layout.ty.is_unsafe_ptr() && dest_layout.ty.is_unsafe_ptr() &&
128+
dest_layout.size != src.layout.size
129+
{
130+
assert_eq!(src.layout.size, 2*self.memory.pointer_size());
131+
assert_eq!(dest_layout.size, self.memory.pointer_size());
132+
assert!(dest_layout.ty.is_unsafe_ptr());
133+
match *src {
134+
Immediate::ScalarPair(data, _) =>
135+
return Ok(data.into()),
136+
Immediate::Scalar(..) =>
137+
bug!(
138+
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
139+
*src, src.layout.ty, dest_layout.ty
140+
),
141+
};
142+
}
143+
144+
// Handle casting any ptr to raw ptr (might be a fat ptr).
145+
if src.layout.ty.is_any_ptr() && dest_layout.ty.is_unsafe_ptr()
146+
{
147+
// The only possible size-unequal case was handled above.
148+
assert_eq!(src.layout.size, dest_layout.size);
149+
return Ok(*src);
158150
}
151+
152+
// For all remaining casts, we either
153+
// (a) cast a raw ptr to usize, or
154+
// (b) cast from an integer-like (including bool, char, enums).
155+
// In both cases we want the bits.
156+
let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
157+
Ok(self.cast_from_int(bits, src.layout, dest_layout)?.into())
159158
}
160159

161160
fn cast_from_int(
@@ -236,31 +235,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
236235
}
237236
}
238237

239-
fn cast_from_ptr(
240-
&self,
241-
ptr: Pointer<M::PointerTag>,
242-
src_layout: TyLayout<'tcx>,
243-
dest_layout: TyLayout<'tcx>,
244-
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
245-
use rustc::ty::TyKind::*;
246-
247-
match dest_layout.ty.sty {
248-
// Casting to a reference or fn pointer is not permitted by rustc,
249-
// no need to support it here.
250-
RawPtr(_) => Ok(ptr.into()),
251-
Int(_) | Uint(_) => {
252-
let size = self.memory.pointer_size();
253-
254-
match self.force_bits(Scalar::Ptr(ptr), size) {
255-
Ok(bits) => self.cast_from_int(bits, src_layout, dest_layout),
256-
Err(_) if dest_layout.size == size => Ok(ptr.into()),
257-
Err(e) => Err(e),
258-
}
259-
}
260-
_ => bug!("invalid MIR: ptr to {:?} cast", dest_layout.ty)
261-
}
262-
}
263-
264238
fn unsize_into_ptr(
265239
&mut self,
266240
src: OpTy<'tcx, M::PointerTag>,

src/librustc_mir/interpret/machine.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
165165
def_id: DefId,
166166
) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;
167167

168-
/// Called for all binary operations on integer(-like) types when one operand is a pointer
169-
/// value, and for the `Offset` operation that is inherently about pointers.
168+
/// Called for all binary operations where the LHS has pointer type.
170169
///
171170
/// Returns a (value, overflowed) pair if the operation succeeded
172-
fn ptr_op(
171+
fn binary_ptr_op(
173172
ecx: &InterpCx<'mir, 'tcx, Self>,
174173
bin_op: mir::BinOp,
175174
left: ImmTy<'tcx, Self::PointerTag>,
@@ -234,7 +233,6 @@ pub trait Machine<'mir, 'tcx>: Sized {
234233
extra: Self::FrameExtra,
235234
) -> InterpResult<'tcx>;
236235

237-
#[inline(always)]
238236
fn int_to_ptr(
239237
_mem: &Memory<'mir, 'tcx, Self>,
240238
int: u64,
@@ -246,11 +244,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
246244
}).into())
247245
}
248246

249-
#[inline(always)]
250247
fn ptr_to_int(
251248
_mem: &Memory<'mir, 'tcx, Self>,
252249
_ptr: Pointer<Self::PointerTag>,
253-
) -> InterpResult<'tcx, u64> {
254-
err!(ReadPointerAsBytes)
255-
}
250+
) -> InterpResult<'tcx, u64>;
256251
}

src/librustc_mir/interpret/operand.rs

+21-12
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,21 @@ pub enum Immediate<Tag=(), Id=AllocId> {
3333
ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
3434
}
3535

36-
impl<'tcx, Tag> Immediate<Tag> {
37-
#[inline]
38-
pub fn from_scalar(val: Scalar<Tag>) -> Self {
39-
Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
36+
impl<Tag> From<ScalarMaybeUndef<Tag>> for Immediate<Tag> {
37+
#[inline(always)]
38+
fn from(val: ScalarMaybeUndef<Tag>) -> Self {
39+
Immediate::Scalar(val)
4040
}
41+
}
4142

43+
impl<Tag> From<Scalar<Tag>> for Immediate<Tag> {
44+
#[inline(always)]
45+
fn from(val: Scalar<Tag>) -> Self {
46+
Immediate::Scalar(val.into())
47+
}
48+
}
49+
50+
impl<'tcx, Tag> Immediate<Tag> {
4251
pub fn new_slice(
4352
val: Scalar<Tag>,
4453
len: u64,
@@ -183,7 +192,7 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
183192
{
184193
#[inline]
185194
pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
186-
ImmTy { imm: Immediate::from_scalar(val), layout }
195+
ImmTy { imm: val.into(), layout }
187196
}
188197

189198
#[inline]
@@ -241,7 +250,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
241250
let ptr = match self.check_mplace_access(mplace, None)? {
242251
Some(ptr) => ptr,
243252
None => return Ok(Some(ImmTy { // zero-sized type
244-
imm: Immediate::Scalar(Scalar::zst().into()),
253+
imm: Scalar::zst().into(),
245254
layout: mplace.layout,
246255
})),
247256
};
@@ -252,7 +261,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
252261
.get(ptr.alloc_id)?
253262
.read_scalar(self, ptr, mplace.layout.size)?;
254263
Ok(Some(ImmTy {
255-
imm: Immediate::Scalar(scalar),
264+
imm: scalar.into(),
256265
layout: mplace.layout,
257266
}))
258267
}
@@ -354,7 +363,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
354363
let field = field.try_into().unwrap();
355364
let field_layout = op.layout.field(self, field)?;
356365
if field_layout.is_zst() {
357-
let immediate = Immediate::Scalar(Scalar::zst().into());
366+
let immediate = Scalar::zst().into();
358367
return Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout });
359368
}
360369
let offset = op.layout.fields.offset(field);
@@ -364,7 +373,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
364373
// extract fields from types with `ScalarPair` ABI
365374
Immediate::ScalarPair(a, b) => {
366375
let val = if offset.bytes() == 0 { a } else { b };
367-
Immediate::Scalar(val)
376+
Immediate::from(val)
368377
},
369378
Immediate::Scalar(val) =>
370379
bug!("field access on non aggregate {:#?}, {:#?}", val, op.layout),
@@ -401,7 +410,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
401410
Deref => self.deref_operand(base)?.into(),
402411
Subslice { .. } | ConstantIndex { .. } | Index(_) => if base.layout.is_zst() {
403412
OpTy {
404-
op: Operand::Immediate(Immediate::Scalar(Scalar::zst().into())),
413+
op: Operand::Immediate(Scalar::zst().into()),
405414
// the actual index doesn't matter, so we just pick a convenient one like 0
406415
layout: base.layout.field(self, 0)?,
407416
}
@@ -425,7 +434,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
425434
let layout = self.layout_of_local(frame, local, layout)?;
426435
let op = if layout.is_zst() {
427436
// Do not read from ZST, they might not be initialized
428-
Operand::Immediate(Immediate::Scalar(Scalar::zst().into()))
437+
Operand::Immediate(Scalar::zst().into())
429438
} else {
430439
frame.locals[local].access()?
431440
};
@@ -553,7 +562,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
553562
Operand::Indirect(MemPlace::from_ptr(ptr, align))
554563
},
555564
ConstValue::Scalar(x) =>
556-
Operand::Immediate(Immediate::Scalar(tag_scalar(x).into())),
565+
Operand::Immediate(tag_scalar(x).into()),
557566
ConstValue::Slice { data, start, end } => {
558567
// We rely on mutability being set correctly in `data` to prevent writes
559568
// where none should happen.

0 commit comments

Comments
 (0)