Promoteds can contain raw pointers, but these must still only point to immutable allocations
This commit is contained in:
parent
632387f38d
commit
10f439a011
6 changed files with 56 additions and 22 deletions
|
@ -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())),
|
||||
|
|
|
@ -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,
|
||||
)?;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
5
src/test/ui/consts/raw_pointer_promoted.rs
Normal file
5
src/test/ui/consts/raw_pointer_promoted.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
// check-pass
|
||||
|
||||
pub const FOO: &'static *const i32 = &(&0 as _);
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue