Skip to content

Commit

Permalink
Promoteds can contain raw pointers, but these must still only point t…
Browse files Browse the repository at this point in the history
…o immutable allocations
  • Loading branch information
oli-obk committed Jan 15, 2020
1 parent 632387f commit 10f439a
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 22 deletions.
4 changes: 2 additions & 2 deletions src/librustc_mir/const_eval.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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())),
Expand Down
13 changes: 9 additions & 4 deletions src/librustc_mir/const_eval/eval_queries.rs
@@ -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};
Expand Down Expand Up @@ -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,
)?;
Expand Down
46 changes: 35 additions & 11 deletions src/librustc_mir/interpret/intern.rs
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/mod.rs
Expand Up @@ -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;
8 changes: 4 additions & 4 deletions src/librustc_mir/transform/const_prop.rs
Expand Up @@ -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};

Expand Down Expand Up @@ -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
}
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/consts/raw_pointer_promoted.rs
@@ -0,0 +1,5 @@
// check-pass

pub const FOO: &'static *const i32 = &(&0 as _);

fn main() {}

0 comments on commit 10f439a

Please sign in to comment.