1
Fork 0

Promoteds can contain raw pointers, but these must still only point to immutable allocations

This commit is contained in:
Oliver Scherer 2019-12-25 13:58:02 +01:00
parent 632387f38d
commit 10f439a011
6 changed files with 56 additions and 22 deletions

View file

@ -5,7 +5,7 @@ use rustc::ty::layout::VariantIdx;
use rustc::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx};
use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx};
mod error;
mod eval_queries;
@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
let loc_ty = tcx.caller_location_ty();
let loc_place = ecx.alloc_caller_location(file, line, col);
intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false).unwrap();
let loc_const = ty::Const {
ty: loc_ty,
val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),

View file

@ -1,9 +1,9 @@
use super::{error_to_const_error, CompileTimeEvalContext, CompileTimeInterpreter, MemoryExtra};
use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{
intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InterpCx,
InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, ScalarMaybeUndef,
StackPopCleanup,
intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InternKind,
InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
ScalarMaybeUndef, StackPopCleanup,
};
use rustc::mir;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
@ -56,9 +56,14 @@ fn eval_body_using_ecx<'mir, 'tcx>(
ecx.run()?;
// Intern the result
let intern_kind = match tcx.static_mutability(cid.instance.def_id()) {
Some(m) => InternKind::Static(m),
None if cid.promoted.is_some() => InternKind::Promoted,
_ => InternKind::Constant,
};
intern_const_alloc_recursive(
ecx,
tcx.static_mutability(cid.instance.def_id()),
intern_kind,
ret,
body.ignore_interior_mut_in_const_validation,
)?;

View file

@ -268,19 +268,27 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
}
}
pub enum InternKind {
/// The `mutability` of the static, ignoring the type which may have interior mutability.
Static(hir::Mutability),
Constant,
Promoted,
ConstProp,
}
pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
ecx: &mut InterpCx<'mir, 'tcx, M>,
// The `mutability` of the place, ignoring the type.
place_mut: Option<hir::Mutability>,
intern_kind: InternKind,
ret: MPlaceTy<'tcx>,
ignore_interior_mut_in_const_validation: bool,
) -> InterpResult<'tcx> {
let tcx = ecx.tcx;
let (base_mutability, base_intern_mode) = match place_mut {
let (base_mutability, base_intern_mode) = match intern_kind {
// `static mut` doesn't care about interior mutability, it's mutable anyway
Some(mutbl) => (mutbl, InternMode::Static),
// consts, promoteds. FIXME: what about array lengths, array initializers?
None => (Mutability::Not, InternMode::ConstBase),
InternKind::Static(mutbl) => (mutbl, InternMode::Static),
// FIXME: what about array lengths, array initializers?
InternKind::Constant | InternKind::ConstProp => (Mutability::Not, InternMode::ConstBase),
InternKind::Promoted => (Mutability::Not, InternMode::ConstBase),
};
// Type based interning.
@ -338,10 +346,23 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
// We can't call the `intern_shallow` method here, as its logic is tailored to safe
// references and a `leftover_allocations` set (where we only have a todo-list here).
// So we hand-roll the interning logic here again.
match base_intern_mode {
InternMode::Static => {}
InternMode::Const | InternMode::ConstBase => {
// If it's not a static, it *must* be immutable.
match intern_kind {
// Mutable statics may contain mutable allocations even behind relocations
InternKind::Static(hir::Mutability::Mut) => {}
// Once we get heap allocations we need to revisit whether immutable statics can
// refer to mutable (e.g. via interior mutability) allocations.
InternKind::Static(hir::Mutability::Not) => {
alloc.mutability = Mutability::Not;
}
// Raw pointers in promoteds may only point to immutable things so we mark
// everything as immutable. Creating a promoted with interior mutability is UB, but
// there's no way we can check whether the user is using raw pointers correctly.
// So all we can do is mark this as immutable here.
InternKind::Promoted => {
alloc.mutability = Mutability::Not;
}
InternKind::Constant | InternKind::ConstProp => {
// If it's a constant, it *must* be immutable.
// We cannot have mutable memory inside a constant.
// We use `delay_span_bug` here, because this can be reached in the presence
// of fancy transmutes.
@ -363,7 +384,10 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
} else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) {
// dangling pointer
throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into()))
} else if ecx.tcx.alloc_map.lock().get(alloc_id).is_none() {
} else if let Some(_) = ecx.tcx.alloc_map.lock().get(alloc_id) {
// FIXME: check if the allocation is ok as per the interning rules as if we interned
// it right here.
} else {
span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id);
}
}

View file

@ -32,6 +32,6 @@ pub use self::visitor::{MutValueVisitor, ValueVisitor};
pub use self::validity::RefTracking;
pub use self::intern::intern_const_alloc_recursive;
pub use self::intern::{intern_const_alloc_recursive, InternKind};
crate use self::intrinsics::eval_nullary_intrinsic;

View file

@ -29,9 +29,9 @@ use syntax::ast::Mutability;
use crate::const_eval::error_to_const_error;
use crate::interpret::{
self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
ScalarMaybeUndef, StackPopCleanup,
self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InternKind,
InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
Pointer, ScalarMaybeUndef, StackPopCleanup,
};
use crate::transform::{MirPass, MirSource};
@ -726,7 +726,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
)) => l.is_bits() && r.is_bits(),
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
let mplace = op.assert_mem_place(&self.ecx);
intern_const_alloc_recursive(&mut self.ecx, None, mplace, false)
intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false)
.expect("failed to intern alloc");
true
}

View file

@ -0,0 +1,5 @@
// check-pass
pub const FOO: &'static *const i32 = &(&0 as _);
fn main() {}