Skip to content

Commit 035c69f

Browse files
committed
switch validation to use operand, not mplace
this means we can get rid of the public allocate_op, and make OpTy only constructible in librustc_mir
1 parent a5baea6 commit 035c69f

File tree

6 files changed

+84
-101
lines changed

6 files changed

+84
-101
lines changed

src/librustc_lint/builtin.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,21 +1614,15 @@ fn validate_const<'a, 'tcx>(
16141614
gid: ::rustc::mir::interpret::GlobalId<'tcx>,
16151615
what: &str,
16161616
) {
1617-
let mut ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
1617+
let ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
16181618
let result = (|| {
1619-
use rustc_target::abi::LayoutOf;
1620-
use rustc_mir::interpret::OpTy;
1621-
1622-
let op = ecx.const_value_to_op(constant.val)?;
1623-
let layout = ecx.layout_of(constant.ty)?;
1624-
let place = ecx.allocate_op(OpTy { op, layout })?.into();
1625-
1626-
let mut todo = vec![(place, Vec::new())];
1619+
let op = ecx.const_to_op(constant)?;
1620+
let mut todo = vec![(op, Vec::new())];
16271621
let mut seen = FxHashSet();
1628-
seen.insert(place);
1629-
while let Some((place, mut path)) = todo.pop() {
1630-
ecx.validate_mplace(
1631-
place,
1622+
seen.insert(op);
1623+
while let Some((op, mut path)) = todo.pop() {
1624+
ecx.validate_operand(
1625+
op,
16321626
&mut path,
16331627
&mut seen,
16341628
&mut todo,

src/librustc_mir/interpret/const_eval.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,6 @@ pub fn op_to_const<'tcx>(
120120
};
121121
Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty))
122122
}
123-
pub fn const_to_op<'tcx>(
124-
ecx: &mut EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
125-
cnst: &'tcx ty::Const<'tcx>,
126-
) -> EvalResult<'tcx, OpTy<'tcx>> {
127-
let op = ecx.const_value_to_op(cnst.val)?;
128-
Ok(OpTy { op, layout: ecx.layout_of(cnst.ty)? })
129-
}
130123

131124
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
132125
tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -351,10 +344,10 @@ pub fn const_field<'a, 'tcx>(
351344
value: &'tcx ty::Const<'tcx>,
352345
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
353346
trace!("const_field: {:?}, {:?}, {:?}", instance, field, value);
354-
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
347+
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
355348
let result = (|| {
356349
// get the operand again
357-
let op = const_to_op(&mut ecx, value)?;
350+
let op = ecx.const_to_op(value)?;
358351
// downcast
359352
let down = match variant {
360353
None => op,
@@ -383,8 +376,8 @@ pub fn const_variant_index<'a, 'tcx>(
383376
val: &'tcx ty::Const<'tcx>,
384377
) -> EvalResult<'tcx, usize> {
385378
trace!("const_variant_index: {:?}, {:?}", instance, val);
386-
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
387-
let op = const_to_op(&mut ecx, val)?;
379+
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
380+
let op = ecx.const_to_op(val)?;
388381
ecx.read_discriminant_as_variant_index(op)
389382
}
390383

src/librustc_mir/interpret/operand.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
//! Functions concerning immediate values and operands, and reading from operands.
1212
//! All high-level functions to read from memory work on operands as sources.
1313
14+
use std::hash::{Hash, Hasher};
1415
use std::convert::TryInto;
1516

16-
use rustc::mir;
17+
use rustc::{mir, ty};
1718
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
1819
use rustc_data_structures::indexed_vec::Idx;
1920

@@ -150,7 +151,7 @@ impl Operand {
150151

151152
#[derive(Copy, Clone, Debug)]
152153
pub struct OpTy<'tcx> {
153-
pub op: Operand,
154+
crate op: Operand, // ideally we'd make this private, but we are not there yet
154155
pub layout: TyLayout<'tcx>,
155156
}
156157

@@ -182,6 +183,20 @@ impl<'tcx> From<ValTy<'tcx>> for OpTy<'tcx> {
182183
}
183184
}
184185

186+
// Validation needs to hash OpTy, but we cannot hash Layout -- so we just hash the type
187+
impl<'tcx> Hash for OpTy<'tcx> {
188+
fn hash<H: Hasher>(&self, state: &mut H) {
189+
self.op.hash(state);
190+
self.layout.ty.hash(state);
191+
}
192+
}
193+
impl<'tcx> PartialEq for OpTy<'tcx> {
194+
fn eq(&self, other: &Self) -> bool {
195+
self.op == other.op && self.layout.ty == other.layout.ty
196+
}
197+
}
198+
impl<'tcx> Eq for OpTy<'tcx> {}
199+
185200
impl<'tcx> OpTy<'tcx> {
186201
#[inline]
187202
pub fn from_ptr(ptr: Pointer, align: Align, layout: TyLayout<'tcx>) -> Self {
@@ -492,7 +507,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
492507
}
493508

494509
// Also used e.g. when miri runs into a constant.
495-
pub fn const_value_to_op(
510+
pub(super) fn const_value_to_op(
496511
&self,
497512
val: ConstValue<'tcx>,
498513
) -> EvalResult<'tcx, Operand> {
@@ -516,6 +531,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
516531
Ok(Operand::Immediate(Value::Scalar(x.into()))),
517532
}
518533
}
534+
pub fn const_to_op(
535+
&self,
536+
cnst: &ty::Const<'tcx>,
537+
) -> EvalResult<'tcx, OpTy<'tcx>> {
538+
let op = self.const_value_to_op(cnst.val)?;
539+
Ok(OpTy { op, layout: self.layout_of(cnst.ty)? })
540+
}
519541

520542
pub(super) fn global_to_op(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Operand> {
521543
let cv = self.const_eval(gid)?;

src/librustc_mir/interpret/place.rs

Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
//! into a place.
1313
//! All high-level functions to write to memory work on places as destinations.
1414
15-
use std::hash::{Hash, Hasher};
1615
use std::convert::TryFrom;
1716

1817
use rustc::mir;
@@ -159,20 +158,6 @@ impl<'tcx> MPlaceTy<'tcx> {
159158
}
160159
}
161160

162-
// Validation needs to hash MPlaceTy, but we cannot hash Layout -- so we just hash the type
163-
impl<'tcx> Hash for MPlaceTy<'tcx> {
164-
fn hash<H: Hasher>(&self, state: &mut H) {
165-
self.mplace.hash(state);
166-
self.layout.ty.hash(state);
167-
}
168-
}
169-
impl<'tcx> PartialEq for MPlaceTy<'tcx> {
170-
fn eq(&self, other: &Self) -> bool {
171-
self.mplace == other.mplace && self.layout.ty == other.layout.ty
172-
}
173-
}
174-
impl<'tcx> Eq for MPlaceTy<'tcx> {}
175-
176161
impl<'tcx> OpTy<'tcx> {
177162
#[inline(always)]
178163
pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx>, Value> {
@@ -681,20 +666,25 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
681666
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
682667
let mplace = match place.place {
683668
Place::Local { frame, local } => {
684-
// FIXME: Consider not doing anything for a ZST, and just returning
685-
// a fake pointer?
686-
687-
// We need the layout of the local. We can NOT use the layout we got,
688-
// that might e.g. be a downcast variant!
689-
let local_layout = self.layout_of_local(frame, local)?;
690-
// Make sure it has a place
691-
let rval = *self.stack[frame].locals[local].access()?;
692-
let mplace = self.allocate_op(OpTy { op: rval, layout: local_layout })?.mplace;
693-
// This might have allocated the flag
694-
*self.stack[frame].locals[local].access_mut()? =
695-
Operand::Indirect(mplace);
696-
// done
697-
mplace
669+
match *self.stack[frame].locals[local].access()? {
670+
Operand::Indirect(mplace) => mplace,
671+
Operand::Immediate(value) => {
672+
// We need to make an allocation.
673+
// FIXME: Consider not doing anything for a ZST, and just returning
674+
// a fake pointer? Are we even called for ZST?
675+
676+
// We need the layout of the local. We can NOT use the layout we got,
677+
// that might e.g. be a downcast variant!
678+
let local_layout = self.layout_of_local(frame, local)?;
679+
let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
680+
self.write_value_to_mplace(value, ptr)?;
681+
let mplace = ptr.mplace;
682+
// Update the local
683+
*self.stack[frame].locals[local].access_mut()? =
684+
Operand::Indirect(mplace);
685+
mplace
686+
}
687+
}
698688
}
699689
Place::Ptr(mplace) => mplace
700690
};
@@ -712,23 +702,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
712702
Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
713703
}
714704

715-
/// Make a place for an operand, allocating if needed
716-
pub fn allocate_op(
717-
&mut self,
718-
OpTy { op, layout }: OpTy<'tcx>,
719-
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
720-
trace!("allocate_op: {:?}", op);
721-
Ok(match op {
722-
Operand::Indirect(mplace) => MPlaceTy { mplace, layout },
723-
Operand::Immediate(value) => {
724-
// FIXME: Is stack always right here?
725-
let ptr = self.allocate(layout, MemoryKind::Stack)?;
726-
self.write_value_to_mplace(value, ptr)?;
727-
ptr
728-
},
729-
})
730-
}
731-
732705
pub fn write_discriminant_value(
733706
&mut self,
734707
variant_index: usize,

src/librustc_mir/interpret/validity.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc::mir::interpret::{
1919
};
2020

2121
use super::{
22-
MPlaceTy, Machine, EvalContext
22+
OpTy, Machine, EvalContext
2323
};
2424

2525
macro_rules! validation_failure{
@@ -187,19 +187,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
187187
}
188188
}
189189

190-
/// This function checks the memory where `dest` points to. The place must be sized
191-
/// (i.e., dest.extra == PlaceExtra::None).
190+
/// This function checks the data at `op`. The operand must be sized.
192191
/// It will error if the bits at the destination do not match the ones described by the layout.
193192
/// The `path` may be pushed to, but the part that is present when the function
194193
/// starts must not be changed!
195-
pub fn validate_mplace(
194+
pub fn validate_operand(
196195
&self,
197-
dest: MPlaceTy<'tcx>,
196+
dest: OpTy<'tcx>,
198197
path: &mut Vec<PathElem>,
199-
seen: &mut FxHashSet<(MPlaceTy<'tcx>)>,
200-
todo: &mut Vec<(MPlaceTy<'tcx>, Vec<PathElem>)>,
198+
seen: &mut FxHashSet<(OpTy<'tcx>)>,
199+
todo: &mut Vec<(OpTy<'tcx>, Vec<PathElem>)>,
201200
) -> EvalResult<'tcx> {
202-
self.memory.dump_alloc(dest.to_ptr()?.alloc_id);
203201
trace!("validate_mplace: {:?}, {:#?}", *dest, dest.layout);
204202

205203
// Find the right variant. We have to handle this as a prelude, not via
@@ -210,16 +208,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
210208
layout::Variants::Tagged { ref tag, .. } => {
211209
let size = tag.value.size(self);
212210
// we first read the tag value as scalar, to be able to validate it
213-
let tag_mplace = self.mplace_field(dest, 0)?;
214-
let tag_value = self.read_scalar(tag_mplace.into())?;
211+
let tag_mplace = self.operand_field(dest, 0)?;
212+
let tag_value = self.read_scalar(tag_mplace)?;
215213
path.push(PathElem::Tag);
216214
self.validate_scalar(
217215
tag_value, size, tag, &path, tag_mplace.layout.ty
218216
)?;
219217
path.pop(); // remove the element again
220218
// then we read it again to get the index, to continue
221219
let variant = self.read_discriminant_as_variant_index(dest.into())?;
222-
let inner_dest = self.mplace_downcast(dest, variant)?;
220+
let inner_dest = self.operand_downcast(dest, variant)?;
223221
// Put the variant projection onto the path, as a field
224222
path.push(PathElem::Field(dest.layout.ty
225223
.ty_adt_def()
@@ -251,7 +249,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
251249
// expectation.
252250
layout::Abi::Scalar(ref scalar_layout) => {
253251
let size = scalar_layout.value.size(self);
254-
let value = self.read_value(dest.into())?;
252+
let value = self.read_value(dest)?;
255253
let scalar = value.to_scalar_or_undef();
256254
self.validate_scalar(scalar, size, scalar_layout, &path, dest.layout.ty)?;
257255
if scalar_layout.value == Primitive::Pointer {
@@ -267,11 +265,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
267265
}
268266
if value.layout.ty.builtin_deref(false).is_some() {
269267
trace!("Recursing below ptr {:#?}", value);
270-
let ptr_place = self.ref_to_mplace(value)?;
271-
// we have not encountered this pointer+layout
272-
// combination before
273-
if seen.insert(ptr_place) {
274-
todo.push((ptr_place, path_clone_and_deref(path)));
268+
let ptr_op = self.ref_to_mplace(value)?.into();
269+
// we have not encountered this pointer+layout combination
270+
// before.
271+
if seen.insert(ptr_op) {
272+
todo.push((ptr_op, path_clone_and_deref(path)));
275273
}
276274
}
277275
}
@@ -286,11 +284,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
286284
// See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
287285
},
288286
layout::FieldPlacement::Array { .. } => {
289-
for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
290-
let field = field?;
291-
path.push(PathElem::ArrayElem(i));
292-
self.validate_mplace(field, path, seen, todo)?;
293-
path.truncate(path_len);
287+
// Skips for ZSTs; we could have an empty array as an immediate
288+
if !dest.layout.is_zst() {
289+
let dest = dest.to_mem_place(); // arrays cannot be immediate
290+
for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
291+
let field = field?;
292+
path.push(PathElem::ArrayElem(i));
293+
self.validate_operand(field.into(), path, seen, todo)?;
294+
path.truncate(path_len);
295+
}
294296
}
295297
},
296298
layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
@@ -311,7 +313,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
311313
_ => return Err(err),
312314
}
313315
};
314-
let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
316+
let unpacked_ptr = self.unpack_unsized_mplace(ptr)?.into();
315317
// for safe ptrs, recursively check it
316318
if !dest.layout.ty.is_unsafe_ptr() {
317319
trace!("Recursing below fat ptr {:?} (unpacked: {:?})", ptr, unpacked_ptr);
@@ -322,9 +324,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
322324
} else {
323325
// Not a pointer, perform regular aggregate handling below
324326
for i in 0..offsets.len() {
325-
let field = self.mplace_field(dest, i as u64)?;
327+
let field = self.operand_field(dest, i as u64)?;
326328
path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
327-
self.validate_mplace(field, path, seen, todo)?;
329+
self.validate_operand(field, path, seen, todo)?;
328330
path.truncate(path_len);
329331
}
330332
// FIXME: For a TyStr, check that this is valid UTF-8.

src/librustc_mir/transform/const_prop.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
257257
source_info: SourceInfo,
258258
) -> Option<Const<'tcx>> {
259259
self.ecx.tcx.span = source_info.span;
260-
match self.ecx.const_value_to_op(c.literal.val) {
260+
match self.ecx.const_to_op(c.literal) {
261261
Ok(op) => {
262-
let layout = self.tcx.layout_of(self.param_env.and(c.literal.ty)).ok()?;
263-
Some((OpTy { op, layout }, c.span))
262+
Some((op, c.span))
264263
},
265264
Err(error) => {
266265
let (stacktrace, span) = self.ecx.generate_stacktrace(None);

0 commit comments

Comments
 (0)