@@ -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,23 @@ 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+ // Mutable statics may contain mutable allocations even behind relocations
351+ InternKind :: Static ( hir:: Mutability :: Mut ) => { }
352+ // Once we get heap allocations we need to revisit whether immutable statics can
353+ // refer to mutable (e.g. via interior mutability) allocations.
354+ InternKind :: Static ( hir:: Mutability :: Not ) => {
355+ alloc. mutability = Mutability :: Not ;
356+ }
357+ // Raw pointers in promoteds may only point to immutable things so we mark
358+ // everything as immutable. Creating a promoted with interior mutability is UB, but
359+ // there's no way we can check whether the user is using raw pointers correctly.
360+ // So all we can do is mark this as immutable here.
361+ InternKind :: Promoted => {
362+ alloc. mutability = Mutability :: Not ;
363+ }
364+ InternKind :: Constant | InternKind :: ConstProp => {
365+ // If it's a constant, it *must* be immutable.
345366 // We cannot have mutable memory inside a constant.
346367 // We use `delay_span_bug` here, because this can be reached in the presence
347368 // of fancy transmutes.
@@ -363,7 +384,10 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
363384 } else if ecx. memory . dead_alloc_map . contains_key ( & alloc_id) {
364385 // dangling pointer
365386 throw_unsup ! ( ValidationFailure ( "encountered dangling pointer in final constant" . into( ) ) )
366- } else if ecx. tcx . alloc_map . lock ( ) . get ( alloc_id) . is_none ( ) {
387+ } else if let Some ( _) = ecx. tcx . alloc_map . lock ( ) . get ( alloc_id) {
388+ // FIXME: check if the allocation is ok as per the interning rules as if we interned
389+ // it right here.
390+ } else {
367391 span_bug ! ( ecx. tcx. span, "encountered unknown alloc id {:?}" , alloc_id) ;
368392 }
369393 }
0 commit comments