Skip to content

Commit 8e917f4

Browse files
committed
Auto merge of #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 d727071 + b9db95e commit 8e917f4

18 files changed

+160
-165
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, 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,
10+
Scalar, InterpResult, PointerArithmetic,
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-
throw_unsup!(ReadPointerAsBytes)
255-
}
250+
) -> InterpResult<'tcx, u64>;
256251
}

src/librustc_mir/interpret/operand.rs

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

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

42+
impl<Tag> From<Scalar<Tag>> for Immediate<Tag> {
43+
#[inline(always)]
44+
fn from(val: Scalar<Tag>) -> Self {
45+
Immediate::Scalar(val.into())
46+
}
47+
}
48+
49+
impl<'tcx, Tag> Immediate<Tag> {
4150
pub fn new_slice(
4251
val: Scalar<Tag>,
4352
len: u64,
@@ -182,7 +191,7 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
182191
{
183192
#[inline]
184193
pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
185-
ImmTy { imm: Immediate::from_scalar(val), layout }
194+
ImmTy { imm: val.into(), layout }
186195
}
187196

188197
#[inline]
@@ -240,7 +249,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
240249
let ptr = match self.check_mplace_access(mplace, None)? {
241250
Some(ptr) => ptr,
242251
None => return Ok(Some(ImmTy { // zero-sized type
243-
imm: Immediate::Scalar(Scalar::zst().into()),
252+
imm: Scalar::zst().into(),
244253
layout: mplace.layout,
245254
})),
246255
};
@@ -251,7 +260,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
251260
.get(ptr.alloc_id)?
252261
.read_scalar(self, ptr, mplace.layout.size)?;
253262
Ok(Some(ImmTy {
254-
imm: Immediate::Scalar(scalar),
263+
imm: scalar.into(),
255264
layout: mplace.layout,
256265
}))
257266
}
@@ -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
};
@@ -556,7 +565,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
556565
Operand::Indirect(MemPlace::from_ptr(ptr, align))
557566
},
558567
ConstValue::Scalar(x) =>
559-
Operand::Immediate(Immediate::Scalar(tag_scalar(x).into())),
568+
Operand::Immediate(tag_scalar(x).into()),
560569
ConstValue::Slice { data, start, end } => {
561570
// We rely on mutability being set correctly in `data` to prevent writes
562571
// where none should happen.

0 commit comments

Comments
 (0)