@@ -268,19 +268,27 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
268
268
}
269
269
}
270
270
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
+
271
279
pub fn intern_const_alloc_recursive < M : CompileTimeMachine < ' mir , ' tcx > > (
272
280
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 ,
275
282
ret : MPlaceTy < ' tcx > ,
276
283
ignore_interior_mut_in_const_validation : bool ,
277
284
) -> InterpResult < ' tcx > {
278
285
let tcx = ecx. tcx ;
279
- let ( base_mutability, base_intern_mode) = match place_mut {
286
+ let ( base_mutability, base_intern_mode) = match intern_kind {
280
287
// `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 ) ,
284
292
} ;
285
293
286
294
// Type based interning.
@@ -338,10 +346,24 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
338
346
// We can't call the `intern_shallow` method here, as its logic is tailored to safe
339
347
// references and a `leftover_allocations` set (where we only have a todo-list here).
340
348
// 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.
345
367
// We cannot have mutable memory inside a constant.
346
368
// We use `delay_span_bug` here, because this can be reached in the presence
347
369
// of fancy transmutes.
@@ -364,6 +386,8 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
364
386
// dangling pointer
365
387
throw_unsup ! ( ValidationFailure ( "encountered dangling pointer in final constant" . into( ) ) )
366
388
} 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.
367
391
span_bug ! ( ecx. tcx. span, "encountered unknown alloc id {:?}" , alloc_id) ;
368
392
}
369
393
}
0 commit comments