@@ -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,43 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
5555 }
5656}
5757
58+ pub enum DisallowInternReason {
59+ ConstHeap ,
60+ }
61+
62+ /// A trait for controlling whether memory allocated in the interpreter can be interned.
63+ ///
64+ /// This prevents us from interning `const_allocate` pointers that have not been made
65+ /// global through `const_make_global`.
66+ pub trait CanIntern {
67+ fn disallows_intern ( & self ) -> Option < DisallowInternReason > ;
68+ }
69+
70+ impl CanIntern for const_eval:: MemoryKind {
71+ fn disallows_intern ( & self ) -> Option < DisallowInternReason > {
72+ match self {
73+ const_eval:: MemoryKind :: Heap { was_made_global : false } => {
74+ Some ( DisallowInternReason :: ConstHeap )
75+ }
76+ const_eval:: MemoryKind :: Heap { was_made_global : true } => None ,
77+ }
78+ }
79+ }
80+
81+ impl CanIntern for ! {
82+ fn disallows_intern ( & self ) -> Option < DisallowInternReason > {
83+ * self
84+ }
85+ }
86+
5887/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
5988///
6089/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the
6190/// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be*
6291/// already mutable (as a sanity check).
6392///
6493/// Returns an iterator over all relocations referred to by this allocation.
65- fn intern_shallow < ' tcx , T , M : CompileTimeMachine < ' tcx , T > > (
94+ fn intern_shallow < ' tcx , T : CanIntern , M : CompileTimeMachine < ' tcx , T > > (
6695 ecx : & mut InterpCx < ' tcx , M > ,
6796 alloc_id : AllocId ,
6897 mutability : Mutability ,
@@ -71,9 +100,26 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
71100 trace ! ( "intern_shallow {:?}" , alloc_id) ;
72101 // remove allocation
73102 // FIXME(#120456) - is `swap_remove` correct?
74- let Some ( ( _kind , mut alloc) ) = ecx. memory . alloc_map . swap_remove ( & alloc_id) else {
103+ let Some ( ( kind , mut alloc) ) = ecx. memory . alloc_map . swap_remove ( & alloc_id) else {
75104 return Err ( ( ) ) ;
76105 } ;
106+
107+ match kind {
108+ MemoryKind :: Machine ( x) if let Some ( reason) = x. disallows_intern ( ) => match reason {
109+ // attempting to intern a `const_allocate`d pointer that was not made global via
110+ // `const_make_global`. We emit an error here but don't return an `Err`. The `Err`
111+ // is for pointers that we can't intern at all (i.e. dangling pointers). We still
112+ // (recursively) intern this pointer because we don't have to worry about the
113+ // additional paperwork involved with _not_ interning it, such as storing it in
114+ // the dead memory map and having to deal with additional "dangling pointer"
115+ // messages if someone tries to store the non-made-global ptr in the final value.
116+ DisallowInternReason :: ConstHeap => {
117+ ecx. tcx . dcx ( ) . emit_err ( ConstHeapPtrInFinal { span : ecx. tcx . span } ) ;
118+ }
119+ } ,
120+ MemoryKind :: Machine ( _) | MemoryKind :: Stack | MemoryKind :: CallerLocation => { }
121+ }
122+
77123 // Set allocation mutability as appropriate. This is used by LLVM to put things into
78124 // read-only memory, and also by Miri when evaluating other globals that
79125 // access this one.
@@ -99,7 +145,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
99145 } else {
100146 ecx. tcx . set_alloc_id_memory ( alloc_id, alloc) ;
101147 }
102- Ok ( alloc. 0 . 0 . provenance ( ) . ptrs ( ) . iter ( ) . map ( |& ( _, prov) | prov) )
148+ Ok ( alloc. inner ( ) . provenance ( ) . ptrs ( ) . iter ( ) . map ( |& ( _, prov) | prov) )
103149}
104150
105151/// Creates a new `DefId` and feeds all the right queries to make this `DefId`
@@ -181,7 +227,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
181227 }
182228 InternKind :: Static ( Mutability :: Not ) => {
183229 (
184- // Outermost allocation is mutable if `!Freeze`.
230+ // Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types .
185231 if ret. layout . ty . is_freeze ( * ecx. tcx , ecx. typing_env ) {
186232 Mutability :: Not
187233 } else {
@@ -321,7 +367,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
321367
322368/// Intern `ret`. This function assumes that `ret` references no other allocation.
323369#[ instrument( level = "debug" , skip( ecx) ) ]
324- pub fn intern_const_alloc_for_constprop < ' tcx , T , M : CompileTimeMachine < ' tcx , T > > (
370+ pub fn intern_const_alloc_for_constprop < ' tcx , T : CanIntern , M : CompileTimeMachine < ' tcx , T > > (
325371 ecx : & mut InterpCx < ' tcx , M > ,
326372 alloc_id : AllocId ,
327373) -> InterpResult < ' tcx , ( ) > {
0 commit comments