@@ -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+
271279pub 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 }
0 commit comments