Skip to content

Commit faf45c5

Browse files
committed
Auto merge of #67603 - oli-obk:no_mut_static_ref_from_const, r=RalfJung
Promoteds can contain raw pointers, but these must still only point to immutable allocations fixes #67601 r? @RalfJung cc @wesleywiser in order to not change behaviour in this PR, const prop uses the constant rules for interning, but at least there's an explicit mode for it now that we can think about this in the future
2 parents 6d0bb91 + 69ffe7b commit faf45c5

File tree

6 files changed

+55
-21
lines changed

6 files changed

+55
-21
lines changed

src/librustc_mir/const_eval.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc::ty::layout::VariantIdx;
55
use rustc::ty::{self, TyCtxt};
66
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
77

8-
use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx};
8+
use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx};
99

1010
mod error;
1111
mod eval_queries;
@@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
5252

5353
let loc_ty = tcx.caller_location_ty();
5454
let loc_place = ecx.alloc_caller_location(file, line, col);
55-
intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
55+
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false).unwrap();
5656
let loc_const = ty::Const {
5757
ty: loc_ty,
5858
val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),

src/librustc_mir/const_eval/eval_queries.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use super::{error_to_const_error, CompileTimeEvalContext, CompileTimeInterpreter, MemoryExtra};
22
use crate::interpret::eval_nullary_intrinsic;
33
use crate::interpret::{
4-
intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InterpCx,
5-
InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, ScalarMaybeUndef,
6-
StackPopCleanup,
4+
intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InternKind,
5+
InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
6+
ScalarMaybeUndef, StackPopCleanup,
77
};
88
use rustc::mir;
99
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
@@ -56,9 +56,14 @@ fn eval_body_using_ecx<'mir, 'tcx>(
5656
ecx.run()?;
5757

5858
// Intern the result
59+
let intern_kind = match tcx.static_mutability(cid.instance.def_id()) {
60+
Some(m) => InternKind::Static(m),
61+
None if cid.promoted.is_some() => InternKind::Promoted,
62+
_ => InternKind::Constant,
63+
};
5964
intern_const_alloc_recursive(
6065
ecx,
61-
tcx.static_mutability(cid.instance.def_id()),
66+
intern_kind,
6267
ret,
6368
body.ignore_interior_mut_in_const_validation,
6469
)?;

src/librustc_mir/interpret/intern.rs

+34-10
Original file line numberDiff line numberDiff line change
@@ -268,19 +268,27 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
268268
}
269269
}
270270

271+
pub enum InternKind {
272+
/// The `mutability` of the static, ignoring the type which may have interior mutability.
273+
Static(hir::Mutability),
274+
Constant,
275+
Promoted,
276+
ConstProp,
277+
}
278+
271279
pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
272280
ecx: &mut InterpCx<'mir, 'tcx, M>,
273-
// The `mutability` of the place, ignoring the type.
274-
place_mut: Option<hir::Mutability>,
281+
intern_kind: InternKind,
275282
ret: MPlaceTy<'tcx>,
276283
ignore_interior_mut_in_const_validation: bool,
277284
) -> InterpResult<'tcx> {
278285
let tcx = ecx.tcx;
279-
let (base_mutability, base_intern_mode) = match place_mut {
286+
let (base_mutability, base_intern_mode) = match intern_kind {
280287
// `static mut` doesn't care about interior mutability, it's mutable anyway
281-
Some(mutbl) => (mutbl, InternMode::Static),
282-
// consts, promoteds. FIXME: what about array lengths, array initializers?
283-
None => (Mutability::Not, InternMode::ConstBase),
288+
InternKind::Static(mutbl) => (mutbl, InternMode::Static),
289+
// FIXME: what about array lengths, array initializers?
290+
InternKind::Constant | InternKind::ConstProp => (Mutability::Not, InternMode::ConstBase),
291+
InternKind::Promoted => (Mutability::Not, InternMode::ConstBase),
284292
};
285293

286294
// Type based interning.
@@ -338,10 +346,24 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
338346
// We can't call the `intern_shallow` method here, as its logic is tailored to safe
339347
// references and a `leftover_allocations` set (where we only have a todo-list here).
340348
// So we hand-roll the interning logic here again.
341-
match base_intern_mode {
342-
InternMode::Static => {}
343-
InternMode::Const | InternMode::ConstBase => {
344-
// If it's not a static, it *must* be immutable.
349+
match intern_kind {
350+
// Statics may contain mutable allocations even behind relocations.
351+
// Even for immutable statics it would be ok to have mutable allocations behind
352+
// raw pointers, e.g. for `static FOO: *const AtomicUsize = &AtomicUsize::new(42)`.
353+
InternKind::Static(_) => {}
354+
// Raw pointers in promoteds may only point to immutable things so we mark
355+
// everything as immutable.
356+
// It is UB to mutate through a raw pointer obtained via an immutable reference.
357+
// Since all references and pointers inside a promoted must by their very definition
358+
// be created from an immutable reference (and promotion also excludes interior
359+
// mutability), mutating through them would be UB.
360+
// There's no way we can check whether the user is using raw pointers correctly,
361+
// so all we can do is mark this as immutable here.
362+
InternKind::Promoted => {
363+
alloc.mutability = Mutability::Not;
364+
}
365+
InternKind::Constant | InternKind::ConstProp => {
366+
// If it's a constant, it *must* be immutable.
345367
// We cannot have mutable memory inside a constant.
346368
// We use `delay_span_bug` here, because this can be reached in the presence
347369
// of fancy transmutes.
@@ -364,6 +386,8 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
364386
// dangling pointer
365387
throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into()))
366388
} else if ecx.tcx.alloc_map.lock().get(alloc_id).is_none() {
389+
// We have hit an `AllocId` that is neither in local or global memory and isn't marked
390+
// as dangling by local memory.
367391
span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id);
368392
}
369393
}

src/librustc_mir/interpret/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ pub use self::visitor::{MutValueVisitor, ValueVisitor};
3232

3333
pub use self::validity::RefTracking;
3434

35-
pub use self::intern::intern_const_alloc_recursive;
35+
pub use self::intern::{intern_const_alloc_recursive, InternKind};
3636

3737
crate use self::intrinsics::eval_nullary_intrinsic;

src/librustc_mir/transform/const_prop.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ use syntax::ast::Mutability;
3030

3131
use crate::const_eval::error_to_const_error;
3232
use crate::interpret::{
33-
self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
34-
LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
35-
ScalarMaybeUndef, StackPopCleanup,
33+
self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InternKind,
34+
InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
35+
Pointer, ScalarMaybeUndef, StackPopCleanup,
3636
};
3737
use crate::transform::{MirPass, MirSource};
3838

@@ -767,7 +767,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
767767
)) => l.is_bits() && r.is_bits(),
768768
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
769769
let mplace = op.assert_mem_place(&self.ecx);
770-
intern_const_alloc_recursive(&mut self.ecx, None, mplace, false)
770+
intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false)
771771
.expect("failed to intern alloc");
772772
true
773773
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// check-pass
2+
3+
pub const FOO: &'static *const i32 = &(&0 as _);
4+
5+
fn main() {}

0 commit comments

Comments
 (0)