mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Use enum instead of boolean
This commit is contained in:
parent
70a914cd34
commit
eb01c3fdd2
@ -1,5 +1,6 @@
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::{self, TyCtxt, Ty, Instance};
|
||||
use syntax::ast::Mutability;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use lvalue::{Global, GlobalId, Lvalue};
|
||||
@ -25,7 +26,12 @@ pub fn eval_body_as_primval<'a, 'tcx>(
|
||||
ecx.tcx,
|
||||
ty::ParamEnv::empty(Reveal::All),
|
||||
mir.span);
|
||||
let cleanup = StackPopCleanup::MarkStatic(mutable);
|
||||
let mutability = if mutable {
|
||||
Mutability::Mutable
|
||||
} else {
|
||||
Mutability::Immutable
|
||||
};
|
||||
let cleanup = StackPopCleanup::MarkStatic(mutability);
|
||||
let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
|
||||
trace!("pushing stack frame for global: {}", name);
|
||||
ecx.push_stack_frame(
|
||||
|
@ -12,7 +12,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
|
||||
use rustc::traits;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use syntax::codemap::{self, DUMMY_SP, Span};
|
||||
use syntax::ast;
|
||||
use syntax::ast::{self, Mutability};
|
||||
use syntax::abi::Abi;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
@ -98,8 +98,7 @@ pub enum StackPopCleanup {
|
||||
/// isn't modifyable afterwards in case of constants.
|
||||
/// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
|
||||
/// references or deallocated
|
||||
/// The bool decides whether the value is mutable (true) or not (false)
|
||||
MarkStatic(bool),
|
||||
MarkStatic(Mutability),
|
||||
/// A regular stackframe added due to a function call will need to get forwarded to the next
|
||||
/// block
|
||||
Goto(mir::BasicBlock),
|
||||
@ -354,23 +353,23 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
// FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
|
||||
Value::ByRef(ptr, _aligned) =>
|
||||
// Alignment does not matter for this call
|
||||
self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, !mutable)?,
|
||||
self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?,
|
||||
Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
|
||||
self.memory.mark_inner_allocation(ptr.alloc_id, !mutable)?;
|
||||
self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
|
||||
},
|
||||
Value::ByValPair(val1, val2) => {
|
||||
if let PrimVal::Ptr(ptr) = val1 {
|
||||
self.memory.mark_inner_allocation(ptr.alloc_id, !mutable)?;
|
||||
self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
|
||||
}
|
||||
if let PrimVal::Ptr(ptr) = val2 {
|
||||
self.memory.mark_inner_allocation(ptr.alloc_id, !mutable)?;
|
||||
self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
|
||||
}
|
||||
},
|
||||
}
|
||||
// see comment on `initialized` field
|
||||
assert!(!global_value.initialized);
|
||||
global_value.initialized = true;
|
||||
assert!(global_value.mutable);
|
||||
assert_eq!(global_value.mutable, Mutability::Mutable);
|
||||
global_value.mutable = mutable;
|
||||
} else {
|
||||
bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue);
|
||||
@ -1023,7 +1022,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
Lvalue::Ptr { .. } => lvalue,
|
||||
Lvalue::Global(cid) => {
|
||||
let global_val = *self.globals.get(&cid).expect("global not cached");
|
||||
let global_val = self.globals.get(&cid).expect("global not cached").clone();
|
||||
match global_val.value {
|
||||
Value::ByRef(ptr, aligned) =>
|
||||
Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None },
|
||||
@ -1033,7 +1032,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
self.write_value_to_ptr(global_val.value, ptr.into(), global_val.ty)?;
|
||||
// see comment on `initialized` field
|
||||
if global_val.initialized {
|
||||
self.memory.mark_static_initalized(ptr.alloc_id, !global_val.mutable)?;
|
||||
self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?;
|
||||
}
|
||||
let lval = self.globals.get_mut(&cid).expect("already checked");
|
||||
*lval = Global {
|
||||
@ -1109,8 +1108,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
match dest {
|
||||
Lvalue::Global(cid) => {
|
||||
let dest = *self.globals.get_mut(&cid).expect("global should be cached");
|
||||
if !dest.mutable {
|
||||
let dest = self.globals.get_mut(&cid).expect("global should be cached").clone();
|
||||
if dest.mutable == Mutability::Immutable {
|
||||
return Err(EvalError::ModifiedConstantMemory);
|
||||
}
|
||||
let write_dest = |this: &mut Self, val| {
|
||||
@ -1595,8 +1594,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
pub fn modify_global<F>(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx>
|
||||
where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
|
||||
{
|
||||
let mut val = *self.globals.get(&cid).expect("global not cached");
|
||||
if !val.mutable {
|
||||
let mut val = self.globals.get(&cid).expect("global not cached").clone();
|
||||
if val.mutable == Mutability::Immutable {
|
||||
return Err(EvalError::ModifiedConstantMemory);
|
||||
}
|
||||
val.value = f(self, val.value)?;
|
||||
|
@ -2,6 +2,7 @@ use rustc::mir;
|
||||
use rustc::ty::layout::{Size, Align};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use syntax::ast::Mutability;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use eval_context::EvalContext;
|
||||
@ -51,7 +52,7 @@ pub struct GlobalId<'tcx> {
|
||||
pub(super) promoted: Option<mir::Promoted>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Global<'tcx> {
|
||||
pub(super) value: Value,
|
||||
/// Only used in `force_allocation` to ensure we don't mark the memory
|
||||
@ -59,7 +60,7 @@ pub struct Global<'tcx> {
|
||||
/// global which initially is `Value::ByVal(PrimVal::Undef)` and gets
|
||||
/// lifted to an allocation before the static is fully initialized
|
||||
pub(super) initialized: bool,
|
||||
pub(super) mutable: bool,
|
||||
pub(super) mutable: Mutability,
|
||||
pub(super) ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
@ -113,13 +114,13 @@ impl<'tcx> Global<'tcx> {
|
||||
pub(super) fn uninitialized(ty: Ty<'tcx>) -> Self {
|
||||
Global {
|
||||
value: Value::ByVal(PrimVal::Undef),
|
||||
mutable: true,
|
||||
mutable: Mutability::Mutable,
|
||||
ty,
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: bool) -> Self {
|
||||
pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: Mutability) -> Self {
|
||||
Global {
|
||||
value,
|
||||
mutable,
|
||||
|
@ -4,6 +4,7 @@ use std::{fmt, iter, ptr, mem, io};
|
||||
|
||||
use rustc::ty;
|
||||
use rustc::ty::layout::{self, TargetDataLayout};
|
||||
use syntax::ast::Mutability;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use value::{PrimVal, self, Pointer};
|
||||
@ -35,7 +36,7 @@ pub struct Allocation {
|
||||
/// The alignment of the allocation to detect unaligned reads.
|
||||
pub align: u64,
|
||||
/// Whether the allocation may be modified.
|
||||
pub mutable: bool,
|
||||
pub mutable: Mutability,
|
||||
/// Use the `mark_static_initalized` method of `Memory` to ensure that an error occurs, if the memory of this
|
||||
/// allocation is modified or deallocated in the future.
|
||||
/// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate`
|
||||
@ -50,6 +51,11 @@ pub enum Kind {
|
||||
C,
|
||||
/// Error if deallocated except during a stack pop
|
||||
Stack,
|
||||
/// Static in the process of being initialized.
|
||||
/// The difference is important: An immutable static referring to a
|
||||
/// mutable initialized static will freeze immutably and would not
|
||||
/// be able to distinguish already initialized statics from uninitialized ones
|
||||
UninitializedStatic,
|
||||
/// May never be deallocated
|
||||
Static,
|
||||
/// Part of env var emulation
|
||||
@ -189,7 +195,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
|
||||
let ptr = self.allocate(bytes.len() as u64, 1, Kind::Static)?;
|
||||
self.write_bytes(PrimVal::Ptr(ptr), bytes)?;
|
||||
self.mark_static_initalized(ptr.alloc_id, true)?;
|
||||
self.mark_static_initalized(ptr.alloc_id, Mutability::Mutable)?;
|
||||
self.literal_alloc_cache.insert(bytes.to_vec(), ptr.alloc_id);
|
||||
Ok(ptr)
|
||||
}
|
||||
@ -213,7 +219,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
undef_mask: UndefMask::new(size),
|
||||
align,
|
||||
kind,
|
||||
mutable: true,
|
||||
mutable: Mutability::Mutable,
|
||||
};
|
||||
let id = self.next_id;
|
||||
self.next_id.0 += 1;
|
||||
@ -404,7 +410,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
|
||||
pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
|
||||
match self.alloc_map.get_mut(&id) {
|
||||
Some(alloc) => if alloc.mutable {
|
||||
Some(alloc) => if alloc.mutable == Mutability::Mutable {
|
||||
Ok(alloc)
|
||||
} else {
|
||||
Err(EvalError::ModifiedConstantMemory)
|
||||
@ -477,8 +483,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
}
|
||||
|
||||
let immutable = match (alloc.kind, alloc.mutable) {
|
||||
(Kind::Static, true) => " (static mut)",
|
||||
(Kind::Static, false) => " (immutable)",
|
||||
(Kind::UninitializedStatic, _) => " (static in the process of initialization)",
|
||||
(Kind::Static, Mutability::Mutable) => " (static mut)",
|
||||
(Kind::Static, Mutability::Immutable) => " (immutable)",
|
||||
(Kind::Env, _) => " (env var)",
|
||||
(Kind::C, _) => " (malloc)",
|
||||
(Kind::Rust, _) => " (heap)",
|
||||
@ -584,31 +591,23 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// mark an allocation pointed to by a static as static and initialized
|
||||
pub fn mark_inner_allocation(&mut self, alloc: AllocId, make_immutable: bool) -> EvalResult<'tcx> {
|
||||
pub fn mark_inner_allocation(&mut self, alloc: AllocId, mutability: Mutability) -> EvalResult<'tcx> {
|
||||
// relocations into other statics are not "inner allocations"
|
||||
if !self.static_alloc.contains(&alloc) {
|
||||
self.mark_static_initalized(alloc, make_immutable)?;
|
||||
self.mark_static_initalized(alloc, mutability)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// mark an allocation as static and initialized, either mutable or not
|
||||
pub fn mark_static_initalized(&mut self, alloc_id: AllocId, make_immutable: bool) -> EvalResult<'tcx> {
|
||||
trace!("mark_static_initalized {:?}, make_immutable: {:?}", alloc_id, make_immutable);
|
||||
pub fn mark_static_initalized(&mut self, alloc_id: AllocId, mutability: Mutability) -> EvalResult<'tcx> {
|
||||
trace!("mark_static_initalized {:?}, mutability: {:?}", alloc_id, mutability);
|
||||
// do not use `self.get_mut(alloc_id)` here, because we might have already marked a
|
||||
// sub-element or have circular pointers (e.g. `Rc`-cycles)
|
||||
let relocations = match self.alloc_map.get_mut(&alloc_id) {
|
||||
Some(&mut Allocation { kind: Kind::Static, ref mut mutable, .. }) => {
|
||||
if make_immutable {
|
||||
*mutable = false;
|
||||
}
|
||||
return Ok(());
|
||||
},
|
||||
Some(&mut Allocation { ref mut relocations, ref mut kind, ref mut mutable, .. }) => {
|
||||
Some(&mut Allocation { ref mut relocations, kind: ref mut kind @ Kind::UninitializedStatic, ref mut mutable, .. }) => {
|
||||
*kind = Kind::Static;
|
||||
if make_immutable {
|
||||
*mutable = false;
|
||||
}
|
||||
*mutable = mutability;
|
||||
// take out the relocations vector to free the borrow on self, so we can call
|
||||
// mark recursively
|
||||
mem::replace(relocations, Default::default())
|
||||
@ -618,7 +617,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
};
|
||||
// recurse into inner allocations
|
||||
for &alloc in relocations.values() {
|
||||
self.mark_inner_allocation(alloc, make_immutable)?;
|
||||
self.mark_inner_allocation(alloc, mutability)?;
|
||||
}
|
||||
// put back the relocations
|
||||
self.alloc_map.get_mut(&alloc_id).expect("checked above").relocations = relocations;
|
||||
|
23
src/step.rs
23
src/step.rs
@ -15,6 +15,7 @@ use eval_context::{EvalContext, StackPopCleanup};
|
||||
use lvalue::{Global, GlobalId, Lvalue};
|
||||
use value::{Value, PrimVal};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ast::Mutability;
|
||||
|
||||
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
|
||||
@ -162,7 +163,7 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
|
||||
def_id: DefId,
|
||||
substs: &'tcx subst::Substs<'tcx>,
|
||||
span: Span,
|
||||
shared: bool,
|
||||
mutability: Mutability,
|
||||
) {
|
||||
let instance = self.ecx.resolve_associated_const(def_id, substs);
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
@ -171,18 +172,22 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
|
||||
}
|
||||
if self.ecx.tcx.has_attr(def_id, "linkage") {
|
||||
trace!("Initializing an extern global with NULL");
|
||||
self.ecx.globals.insert(cid, Global::initialized(self.ecx.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), !shared));
|
||||
self.ecx.globals.insert(cid, Global::initialized(self.ecx.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), mutability));
|
||||
return;
|
||||
}
|
||||
self.try(|this| {
|
||||
let mir = this.ecx.load_mir(instance.def)?;
|
||||
this.ecx.globals.insert(cid, Global::uninitialized(mir.return_ty));
|
||||
let mutable = !shared ||
|
||||
!mir.return_ty.is_freeze(
|
||||
let internally_mutable = !mir.return_ty.is_freeze(
|
||||
this.ecx.tcx,
|
||||
ty::ParamEnv::empty(Reveal::All),
|
||||
span);
|
||||
let cleanup = StackPopCleanup::MarkStatic(mutable);
|
||||
let mutability = if mutability == Mutability::Mutable || internally_mutable {
|
||||
Mutability::Mutable
|
||||
} else {
|
||||
Mutability::Immutable
|
||||
};
|
||||
let cleanup = StackPopCleanup::MarkStatic(mutability);
|
||||
let name = ty::tls::with(|tcx| tcx.item_path_str(def_id));
|
||||
trace!("pushing stack frame for global: {}", name);
|
||||
this.ecx.push_stack_frame(
|
||||
@ -214,7 +219,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
|
||||
// already computed by rustc
|
||||
mir::Literal::Value { .. } => {}
|
||||
mir::Literal::Item { def_id, substs } => {
|
||||
self.global_item(def_id, substs, constant.span, true);
|
||||
self.global_item(def_id, substs, constant.span, Mutability::Immutable);
|
||||
},
|
||||
mir::Literal::Promoted { index } => {
|
||||
let cid = GlobalId {
|
||||
@ -233,7 +238,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
|
||||
constant.span,
|
||||
mir,
|
||||
Lvalue::Global(cid),
|
||||
StackPopCleanup::MarkStatic(false),
|
||||
StackPopCleanup::MarkStatic(Mutability::Immutable),
|
||||
)
|
||||
});
|
||||
}
|
||||
@ -254,7 +259,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
|
||||
if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) {
|
||||
if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
|
||||
if let hir::ItemStatic(_, m, _) = *node {
|
||||
self.global_item(def_id, substs, span, m == hir::MutImmutable);
|
||||
self.global_item(def_id, substs, span, if m == hir::MutMutable { Mutability::Mutable } else { Mutability::Immutable });
|
||||
return;
|
||||
} else {
|
||||
bug!("static def id doesn't point to static");
|
||||
@ -265,7 +270,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
|
||||
} else {
|
||||
let def = self.ecx.tcx.describe_def(def_id).expect("static not found");
|
||||
if let hir::def::Def::Static(_, mutable) = def {
|
||||
self.global_item(def_id, substs, span, !mutable);
|
||||
self.global_item(def_id, substs, span, if mutable { Mutability::Mutable } else { Mutability::Immutable });
|
||||
} else {
|
||||
bug!("static found but isn't a static: {:?}", def);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, Ty};
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{self, Mutability};
|
||||
|
||||
use error::{EvalResult, EvalError};
|
||||
|
||||
@ -68,7 +68,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
self.memory.mark_static_initalized(vtable.alloc_id, true)?;
|
||||
self.memory.mark_static_initalized(vtable.alloc_id, Mutability::Mutable)?;
|
||||
|
||||
Ok(vtable)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user