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::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; 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 error;
mod eval_queries; mod eval_queries;
@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
let loc_ty = tcx.caller_location_ty(); let loc_ty = tcx.caller_location_ty();
let loc_place = ecx.alloc_caller_location(file, line, col); 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 { let loc_const = ty::Const {
ty: loc_ty, ty: loc_ty,
val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())), 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 super::{error_to_const_error, CompileTimeEvalContext, CompileTimeInterpreter, MemoryExtra};
use crate::interpret::eval_nullary_intrinsic; use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{ use crate::interpret::{
intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InterpCx, intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InternKind,
InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, ScalarMaybeUndef, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
StackPopCleanup, ScalarMaybeUndef, StackPopCleanup,
}; };
use rustc::mir; use rustc::mir;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled}; use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
@ -56,9 +56,14 @@ fn eval_body_using_ecx<'mir, 'tcx>(
ecx.run()?; ecx.run()?;
// Intern the result // 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( intern_const_alloc_recursive(
ecx, ecx,
tcx.static_mutability(cid.instance.def_id()), intern_kind,
ret, ret,
body.ignore_interior_mut_in_const_validation, 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>>( pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
ecx: &mut InterpCx<'mir, 'tcx, M>, ecx: &mut InterpCx<'mir, 'tcx, M>,
// The `mutability` of the place, ignoring the type. intern_kind: InternKind,
place_mut: Option<hir::Mutability>,
ret: MPlaceTy<'tcx>, ret: MPlaceTy<'tcx>,
ignore_interior_mut_in_const_validation: bool, ignore_interior_mut_in_const_validation: bool,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let tcx = ecx.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 // `static mut` doesn't care about interior mutability, it's mutable anyway
Some(mutbl) => (mutbl, InternMode::Static), InternKind::Static(mutbl) => (mutbl, InternMode::Static),
// consts, promoteds. FIXME: what about array lengths, array initializers? // FIXME: what about array lengths, array initializers?
None => (Mutability::Not, InternMode::ConstBase), InternKind::Constant | InternKind::ConstProp => (Mutability::Not, InternMode::ConstBase),
InternKind::Promoted => (Mutability::Not, InternMode::ConstBase),
}; };
// Type based interning. // 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 // 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). // references and a `leftover_allocations` set (where we only have a todo-list here).
// So we hand-roll the interning logic here again. // So we hand-roll the interning logic here again.
match base_intern_mode { match intern_kind {
InternMode::Static => {} // Mutable statics may contain mutable allocations even behind relocations
InternMode::Const | InternMode::ConstBase => { InternKind::Static(hir::Mutability::Mut) => {}
// If it's not a static, it *must* be immutable. // 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 cannot have mutable memory inside a constant.
// We use `delay_span_bug` here, because this can be reached in the presence // We use `delay_span_bug` here, because this can be reached in the presence
// of fancy transmutes. // 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) { } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) {
// dangling pointer // dangling pointer
throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into())) 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); 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::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; 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::const_eval::error_to_const_error;
use crate::interpret::{ use crate::interpret::{
self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InternKind,
LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
ScalarMaybeUndef, StackPopCleanup, Pointer, ScalarMaybeUndef, StackPopCleanup,
}; };
use crate::transform::{MirPass, MirSource}; use crate::transform::{MirPass, MirSource};
@ -726,7 +726,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
)) => l.is_bits() && r.is_bits(), )) => l.is_bits() && r.is_bits(),
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => { interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
let mplace = op.assert_mem_place(&self.ecx); 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"); .expect("failed to intern alloc");
true true
} }

View file

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