@@ -31,7 +31,7 @@ use super::{
3131} ;
3232use crate :: const_eval;
3333use crate :: const_eval:: DummyMachine ;
34- use crate :: errors:: NestedStaticInThreadLocal ;
34+ use crate :: errors:: { ConstHeapPtrInFinal , NestedStaticInThreadLocal } ;
3535
3636pub trait CompileTimeMachine < ' tcx , T > = Machine <
3737 ' tcx ,
@@ -55,14 +55,37 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
5555 }
5656}
5757
58+ pub enum DisallowInternReason {
59+ ConstHeap ,
60+ }
61+
62+ pub trait CanIntern {
63+ fn disallows_intern ( & self ) -> Option < DisallowInternReason > ;
64+ }
65+
66+ impl CanIntern for const_eval:: MemoryKind {
67+ fn disallows_intern ( & self ) -> Option < DisallowInternReason > {
68+ match self {
69+ const_eval:: MemoryKind :: Heap { was_made_immut : false } => Some ( DisallowInternReason :: ConstHeap ) ,
70+ const_eval:: MemoryKind :: Heap { was_made_immut : true } => None ,
71+ }
72+ }
73+ }
74+
75+ impl CanIntern for ! {
76+ fn disallows_intern ( & self ) -> Option < DisallowInternReason > {
77+ * self
78+ }
79+ }
80+
5881/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
5982///
6083/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the
6184/// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be*
6285/// already mutable (as a sanity check).
6386///
6487/// Returns an iterator over all relocations referred to by this allocation.
65- fn intern_shallow < ' tcx , T , M : CompileTimeMachine < ' tcx , T > > (
88+ fn intern_shallow < ' tcx , T : CanIntern , M : CompileTimeMachine < ' tcx , T > > (
6689 ecx : & mut InterpCx < ' tcx , M > ,
6790 alloc_id : AllocId ,
6891 mutability : Mutability ,
@@ -71,9 +94,22 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
7194 trace ! ( "intern_shallow {:?}" , alloc_id) ;
7295 // remove allocation
7396 // FIXME(#120456) - is `swap_remove` correct?
74- let Some ( ( _kind , mut alloc) ) = ecx. memory . alloc_map . swap_remove ( & alloc_id) else {
97+ let Some ( ( kind , mut alloc) ) = ecx. memory . alloc_map . swap_remove ( & alloc_id) else {
7598 return Err ( ( ) ) ;
7699 } ;
100+
101+ match kind {
102+ MemoryKind :: Machine ( x) if let Some ( reason) = x. disallows_intern ( ) => match reason {
103+ // attempting to intern a `const_allocate`d pointer that was not made global via
104+ // `const_make_global`. We emit an error here but don't return an `Err` as if we
105+ // did the caller assumes we found a dangling pointer.
106+ DisallowInternReason :: ConstHeap => {
107+ ecx. tcx . dcx ( ) . emit_err ( ConstHeapPtrInFinal { span : ecx. tcx . span } ) ;
108+ }
109+ } ,
110+ MemoryKind :: Machine ( _) | MemoryKind :: Stack | MemoryKind :: CallerLocation => { }
111+ }
112+
77113 // Set allocation mutability as appropriate. This is used by LLVM to put things into
78114 // read-only memory, and also by Miri when evaluating other globals that
79115 // access this one.
@@ -99,7 +135,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
99135 } else {
100136 ecx. tcx . set_alloc_id_memory ( alloc_id, alloc) ;
101137 }
102- Ok ( alloc. 0 . 0 . provenance ( ) . ptrs ( ) . iter ( ) . map ( |& ( _, prov) | prov) )
138+ Ok ( alloc. inner ( ) . provenance ( ) . ptrs ( ) . iter ( ) . map ( |& ( _, prov) | prov) )
103139}
104140
105141/// Creates a new `DefId` and feeds all the right queries to make this `DefId`
@@ -181,7 +217,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
181217 }
182218 InternKind :: Static ( Mutability :: Not ) => {
183219 (
184- // Outermost allocation is mutable if `!Freeze`.
220+ // Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types .
185221 if ret. layout . ty . is_freeze ( * ecx. tcx , ecx. typing_env ) {
186222 Mutability :: Not
187223 } else {
@@ -309,7 +345,12 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
309345 // `static mut`.
310346 just_interned. insert ( alloc_id) ;
311347 match intern_shallow ( ecx, alloc_id, inner_mutability, Some ( & mut disambiguator) ) {
312- Ok ( nested) => todo. extend ( nested) ,
348+ Ok ( nested) => {
349+ // filtering here is necessary for self-referential values created through
350+ // `const_allocate`.
351+ // see tests/ui/consts/const-eval/heap/make-global-cyclic.rs
352+ todo. extend ( nested. filter ( |prov| !just_interned. contains ( & prov. alloc_id ( ) ) ) )
353+ }
313354 Err ( ( ) ) => {
314355 ecx. tcx . dcx ( ) . delayed_bug ( "found dangling pointer during const interning" ) ;
315356 result = Err ( InternResult :: FoundDanglingPointer ) ;
@@ -321,7 +362,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
321362
322363/// Intern `ret`. This function assumes that `ret` references no other allocation.
323364#[ instrument( level = "debug" , skip( ecx) ) ]
324- pub fn intern_const_alloc_for_constprop < ' tcx , T , M : CompileTimeMachine < ' tcx , T > > (
365+ pub fn intern_const_alloc_for_constprop < ' tcx , T : CanIntern , M : CompileTimeMachine < ' tcx , T > > (
325366 ecx : & mut InterpCx < ' tcx , M > ,
326367 alloc_id : AllocId ,
327368) -> InterpResult < ' tcx , ( ) > {
0 commit comments