Skip to content

Commit 880f633

Browse files
authored
Rollup merge of #58000 - oli-obk:fixes_and_cleanups, r=RalfJung
Fixes and cleanups Address the points raised in https://github.com/rust-lang/rust/pull/57677/files by @eddyb and @RalfJung
2 parents bb91a19 + 8c26c59 commit 880f633

File tree

7 files changed

+77
-45
lines changed

7 files changed

+77
-45
lines changed

src/librustc/mir/interpret/value.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub struct RawConst<'tcx> {
1414
}
1515

1616
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
17-
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
17+
/// matches the LocalState optimizations for easy conversions between Value and ConstValue.
1818
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
1919
pub enum ConstValue<'tcx> {
2020
/// Used only for types with layout::abi::Scalar ABI and ZSTs

src/librustc_mir/interpret/eval_context.rs

+44-28
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
7676
/// The locals are stored as `Option<Value>`s.
7777
/// `None` represents a local that is currently dead, while a live local
7878
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
79-
pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
80-
pub local_layouts: IndexVec<mir::Local, Cell<Option<TyLayout<'tcx>>>>,
79+
pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
8180

8281
////////////////////////////////////////////////////////////////////////////////
8382
// Current position within the function
@@ -106,7 +105,15 @@ pub enum StackPopCleanup {
106105
None { cleanup: bool },
107106
}
108107

109-
// State of a local variable
108+
/// State of a local variable including a memoized layout
109+
#[derive(Clone, PartialEq, Eq)]
110+
pub struct LocalState<'tcx, Tag=(), Id=AllocId> {
111+
pub state: LocalValue<Tag, Id>,
112+
/// Don't modify if `Some`, this is only used to prevent computing the layout twice
113+
pub layout: Cell<Option<TyLayout<'tcx>>>,
114+
}
115+
116+
/// State of a local variable
110117
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
111118
pub enum LocalValue<Tag=(), Id=AllocId> {
112119
Dead,
@@ -117,16 +124,16 @@ pub enum LocalValue<Tag=(), Id=AllocId> {
117124
Live(Operand<Tag, Id>),
118125
}
119126

120-
impl<'tcx, Tag> LocalValue<Tag> {
127+
impl<'tcx, Tag> LocalState<'tcx, Tag> {
121128
pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
122-
match self {
129+
match self.state {
123130
LocalValue::Dead => err!(DeadLocal),
124131
LocalValue::Live(ref val) => Ok(val),
125132
}
126133
}
127134

128135
pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> {
129-
match self {
136+
match self.state {
130137
LocalValue::Dead => err!(DeadLocal),
131138
LocalValue::Live(ref mut val) => Ok(val),
132139
}
@@ -310,17 +317,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
310317
pub fn layout_of_local(
311318
&self,
312319
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
313-
local: mir::Local
320+
local: mir::Local,
321+
layout: Option<TyLayout<'tcx>>,
314322
) -> EvalResult<'tcx, TyLayout<'tcx>> {
315-
let cell = &frame.local_layouts[local];
316-
if cell.get().is_none() {
317-
let local_ty = frame.mir.local_decls[local].ty;
318-
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
319-
let layout = self.layout_of(local_ty)?;
320-
cell.set(Some(layout));
323+
match frame.locals[local].layout.get() {
324+
None => {
325+
let layout = ::interpret::operand::from_known_layout(layout, || {
326+
let local_ty = frame.mir.local_decls[local].ty;
327+
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
328+
self.layout_of(local_ty)
329+
})?;
330+
frame.locals[local].layout.set(Some(layout));
331+
Ok(layout)
332+
}
333+
Some(layout) => Ok(layout),
321334
}
322-
323-
Ok(cell.get().unwrap())
324335
}
325336

326337
pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
@@ -454,7 +465,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
454465
// empty local array, we fill it in below, after we are inside the stack frame and
455466
// all methods actually know about the frame
456467
locals: IndexVec::new(),
457-
local_layouts: IndexVec::from_elem_n(Default::default(), mir.local_decls.len()),
458468
span,
459469
instance,
460470
stmt: 0,
@@ -466,12 +476,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
466476
// We put some marker immediate into the locals that we later want to initialize.
467477
// This can be anything except for LocalValue::Dead -- because *that* is the
468478
// value we use for things that we know are initially dead.
469-
let dummy =
470-
LocalValue::Live(Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef)));
479+
let dummy = LocalState {
480+
state: LocalValue::Live(Operand::Immediate(Immediate::Scalar(
481+
ScalarMaybeUndef::Undef,
482+
))),
483+
layout: Cell::new(None),
484+
};
471485
let mut locals = IndexVec::from_elem(dummy, &mir.local_decls);
472486
// Return place is handled specially by the `eval_place` functions, and the
473487
// entry in `locals` should never be used. Make it dead, to be sure.
474-
locals[mir::RETURN_PLACE] = LocalValue::Dead;
488+
locals[mir::RETURN_PLACE].state = LocalValue::Dead;
475489
// Now mark those locals as dead that we do not want to initialize
476490
match self.tcx.describe_def(instance.def_id()) {
477491
// statics and constants don't have `Storage*` statements, no need to look for them
@@ -484,7 +498,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
484498
match stmt.kind {
485499
StorageLive(local) |
486500
StorageDead(local) => {
487-
locals[local] = LocalValue::Dead;
501+
locals[local].state = LocalValue::Dead;
488502
}
489503
_ => {}
490504
}
@@ -494,11 +508,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
494508
}
495509
// Finally, properly initialize all those that still have the dummy value
496510
for (idx, local) in locals.iter_enumerated_mut() {
497-
match *local {
511+
match local.state {
498512
LocalValue::Live(_) => {
499-
// This needs to be peoperly initialized.
500-
let layout = self.layout_of_local(self.frame(), idx)?;
501-
*local = LocalValue::Live(self.uninit_operand(layout)?);
513+
// This needs to be properly initialized.
514+
let ty = self.monomorphize(mir.local_decls[idx].ty)?;
515+
let layout = self.layout_of(ty)?;
516+
local.state = LocalValue::Live(self.uninit_operand(layout)?);
517+
local.layout = Cell::new(Some(layout));
502518
}
503519
LocalValue::Dead => {
504520
// Nothing to do
@@ -543,7 +559,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
543559
}
544560
// Deallocate all locals that are backed by an allocation.
545561
for local in frame.locals {
546-
self.deallocate_local(local)?;
562+
self.deallocate_local(local.state)?;
547563
}
548564
// Validate the return value. Do this after deallocating so that we catch dangling
549565
// references.
@@ -591,10 +607,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
591607
assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
592608
trace!("{:?} is now live", local);
593609

594-
let layout = self.layout_of_local(self.frame(), local)?;
610+
let layout = self.layout_of_local(self.frame(), local, None)?;
595611
let init = LocalValue::Live(self.uninit_operand(layout)?);
596612
// StorageLive *always* kills the value that's currently stored
597-
Ok(mem::replace(&mut self.frame_mut().locals[local], init))
613+
Ok(mem::replace(&mut self.frame_mut().locals[local].state, init))
598614
}
599615

600616
/// Returns the old value of the local.
@@ -603,7 +619,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
603619
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
604620
trace!("{:?} is now dead", local);
605621

606-
mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead)
622+
mem::replace(&mut self.frame_mut().locals[local].state, LocalValue::Dead)
607623
}
608624

609625
pub(super) fn deallocate_local(

src/librustc_mir/interpret/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ mod visitor;
1818
pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
1919

2020
pub use self::eval_context::{
21-
EvalContext, Frame, StackPopCleanup, LocalValue,
21+
EvalContext, Frame, StackPopCleanup, LocalState, LocalValue,
2222
};
2323

2424
pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};

src/librustc_mir/interpret/operand.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl<'tcx, Tag> OpTy<'tcx, Tag>
227227
// Use the existing layout if given (but sanity check in debug mode),
228228
// or compute the layout.
229229
#[inline(always)]
230-
fn from_known_layout<'tcx>(
230+
pub(super) fn from_known_layout<'tcx>(
231231
layout: Option<TyLayout<'tcx>>,
232232
compute: impl FnOnce() -> EvalResult<'tcx, TyLayout<'tcx>>
233233
) -> EvalResult<'tcx, TyLayout<'tcx>> {
@@ -457,14 +457,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
457457
}
458458

459459
/// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local
460-
fn access_local(
460+
pub fn access_local(
461461
&self,
462462
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
463463
local: mir::Local,
464+
layout: Option<TyLayout<'tcx>>,
464465
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
465466
assert_ne!(local, mir::RETURN_PLACE);
466467
let op = *frame.locals[local].access()?;
467-
let layout = self.layout_of_local(frame, local)?;
468+
let layout = self.layout_of_local(frame, local, layout)?;
468469
Ok(OpTy { op, layout })
469470
}
470471

@@ -473,14 +474,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
473474
fn eval_place_to_op(
474475
&self,
475476
mir_place: &mir::Place<'tcx>,
477+
layout: Option<TyLayout<'tcx>>,
476478
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
477479
use rustc::mir::Place::*;
478480
let op = match *mir_place {
479481
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
480-
Local(local) => self.access_local(self.frame(), local)?,
482+
Local(local) => self.access_local(self.frame(), local, layout)?,
481483

482484
Projection(ref proj) => {
483-
let op = self.eval_place_to_op(&proj.base)?;
485+
let op = self.eval_place_to_op(&proj.base, None)?;
484486
self.operand_projection(op, &proj.elem)?
485487
}
486488

@@ -504,7 +506,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
504506
// FIXME: do some more logic on `move` to invalidate the old location
505507
Copy(ref place) |
506508
Move(ref place) =>
507-
self.eval_place_to_op(place)?,
509+
self.eval_place_to_op(place, layout)?,
508510

509511
Constant(ref constant) => {
510512
let layout = from_known_layout(layout, || {

src/librustc_mir/interpret/place.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ where
624624
// their layout on return.
625625
PlaceTy {
626626
place: *return_place,
627-
layout: self.layout_of_local(self.frame(), mir::RETURN_PLACE)?,
627+
layout: self.layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
628628
},
629629
None => return err!(InvalidNullPointerUsage),
630630
},
@@ -633,7 +633,7 @@ where
633633
frame: self.cur_frame(),
634634
local,
635635
},
636-
layout: self.layout_of_local(self.frame(), local)?,
636+
layout: self.layout_of_local(self.frame(), local, None)?,
637637
},
638638

639639
Projection(ref proj) => {
@@ -901,7 +901,7 @@ where
901901
// We need the layout of the local. We can NOT use the layout we got,
902902
// that might e.g., be an inner field of a struct with `Scalar` layout,
903903
// that has different alignment than the outer field.
904-
let local_layout = self.layout_of_local(&self.stack[frame], local)?;
904+
let local_layout = self.layout_of_local(&self.stack[frame], local, None)?;
905905
let ptr = self.allocate(local_layout, MemoryKind::Stack);
906906
// We don't have to validate as we can assume the local
907907
// was already valid for its type.

src/librustc_mir/interpret/snapshot.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2323
use syntax::ast::Mutability;
2424
use syntax::source_map::Span;
2525

26-
use super::eval_context::{LocalValue, StackPopCleanup};
27-
use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef};
26+
use super::eval_context::{LocalState, StackPopCleanup};
27+
use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef, LocalValue};
2828
use const_eval::CompileTimeInterpreter;
2929

3030
#[derive(Default)]
@@ -321,7 +321,6 @@ impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> {
321321
return_to_block,
322322
return_place -> (return_place.as_ref().map(|r| &**r)),
323323
locals,
324-
local_layouts -> _,
325324
block,
326325
stmt,
327326
extra,
@@ -340,7 +339,6 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
340339
return_to_block,
341340
return_place,
342341
locals,
343-
local_layouts: _,
344342
block,
345343
stmt,
346344
extra: _,
@@ -358,6 +356,22 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
358356
}
359357
}
360358

359+
impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx>
360+
where Ctx: SnapshotContext<'a>,
361+
{
362+
type Item = LocalValue<(), AllocIdSnapshot<'a>>;
363+
364+
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
365+
let LocalState { state, layout: _ } = self;
366+
state.snapshot(ctx)
367+
}
368+
}
369+
370+
impl_stable_hash_for!(struct LocalState<'tcx> {
371+
state,
372+
layout -> _,
373+
});
374+
361375
impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b>
362376
for Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
363377
{

src/librustc_mir/interpret/terminator.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
309309
mir.spread_arg,
310310
mir.args_iter()
311311
.map(|local|
312-
(local, self.layout_of_local(self.frame(), local).unwrap().ty)
312+
(local, self.layout_of_local(self.frame(), local, None).unwrap().ty)
313313
)
314314
.collect::<Vec<_>>()
315315
);
@@ -383,7 +383,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
383383
}
384384
} else {
385385
let callee_layout =
386-
self.layout_of_local(self.frame(), mir::RETURN_PLACE)?;
386+
self.layout_of_local(self.frame(), mir::RETURN_PLACE, None)?;
387387
if !callee_layout.abi.is_uninhabited() {
388388
return err!(FunctionRetMismatch(
389389
self.tcx.types.never, callee_layout.ty

0 commit comments

Comments
 (0)