@@ -125,10 +125,11 @@ pub fn intern_const_alloc_recursive<
125125
126126 // Intern the base allocation, and initialize todo list for recursive interning.
127127 let base_alloc_id = ret. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) ;
128- let mut todo = vec ! [ ( base_alloc_id, base_mutability) ] ;
128+ let mut todo: Vec < _ > =
129+ intern_shallow ( ecx, base_alloc_id, base_mutability) . unwrap ( ) . map ( |prov| prov) . collect ( ) ;
129130 // We need to distinguish "has just been interned" from "was already in `tcx`",
130131 // so we track this in a separate set.
131- let mut just_interned = FxHashSet :: default ( ) ;
132+ let mut just_interned: FxHashSet < _ > = std :: iter :: once ( base_alloc_id ) . collect ( ) ;
132133 // Whether we encountered a bad mutable pointer.
133134 // We want to first report "dangling" and then "mutable", so we need to delay reporting these
134135 // errors.
@@ -142,52 +143,49 @@ pub fn intern_const_alloc_recursive<
142143 // raw pointers, so we cannot rely on validation to catch them -- and since interning runs
143144 // before validation, and interning doesn't know the type of anything, this means we can't show
144145 // better errors. Maybe we should consider doing validation before interning in the future.
145- while let Some ( ( alloc_id, mutability) ) = todo. pop ( ) {
146+ while let Some ( prov) = todo. pop ( ) {
147+ let alloc_id = prov. alloc_id ( ) ;
148+ if intern_kind != InternKind :: Promoted
149+ && inner_mutability == Mutability :: Not
150+ && !prov. immutable ( )
151+ {
152+ if ecx. tcx . try_get_global_alloc ( alloc_id) . is_some ( )
153+ && !just_interned. contains ( & alloc_id)
154+ {
155+ // This is a pointer to some memory from another constant. We encounter mutable
156+ // pointers to such memory since we do not always track immutability through
157+ // these "global" pointers. Allowing them is harmless; the point of these checks
158+ // during interning is to justify why we intern the *new* allocations immutably,
159+ // so we can completely ignore existing allocations. We also don't need to add
160+ // this to the todo list, since after all it is already interned.
161+ continue ;
162+ }
163+ // Found a mutable pointer inside a const where inner allocations should be
164+ // immutable. We exclude promoteds from this, since things like `&mut []` and
165+ // `&None::<Cell<i32>>` lead to promotion that can produce mutable pointers. We rely
166+ // on the promotion analysis not screwing up to ensure that it is sound to intern
167+ // promoteds as immutable.
168+ found_bad_mutable_pointer = true ;
169+ }
146170 if ecx. tcx . try_get_global_alloc ( alloc_id) . is_some ( ) {
147171 // Already interned.
148172 debug_assert ! ( !ecx. memory. alloc_map. contains_key( & alloc_id) ) ;
149173 continue ;
150174 }
151175 just_interned. insert ( alloc_id) ;
152- let provs = intern_shallow ( ecx, alloc_id, mutability) . map_err ( |( ) | {
176+ // We always intern with `inner_mutability`, and furthermore we ensured above that if
177+ // that is "immutable", then there are *no* mutable pointers anywhere in the newly
178+ // interned memory -- justifying that we can indeed intern immutably. However this also
179+ // means we can *not* easily intern immutably here if `prov.immutable()` is true and
180+ // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and
181+ // we'd have to somehow check that they are *all* immutable before deciding that this
182+ // allocation can be made immutable. In the future we could consider analyzing all
183+ // pointers before deciding which allocations can be made immutable; but for now we are
184+ // okay with losing some potential for immutability here. This can anyway only affect
185+ // `static mut`.
186+ todo. extend ( intern_shallow ( ecx, alloc_id, inner_mutability) . map_err ( |( ) | {
153187 ecx. tcx . dcx ( ) . emit_err ( DanglingPtrInFinal { span : ecx. tcx . span , kind : intern_kind } )
154- } ) ?;
155- for prov in provs {
156- let alloc_id = prov. alloc_id ( ) ;
157- if intern_kind != InternKind :: Promoted
158- && inner_mutability == Mutability :: Not
159- && !prov. immutable ( )
160- {
161- if ecx. tcx . try_get_global_alloc ( alloc_id) . is_some ( )
162- && !just_interned. contains ( & alloc_id)
163- {
164- // This is a pointer to some memory from another constant. We encounter mutable
165- // pointers to such memory since we do not always track immutability through
166- // these "global" pointers. Allowing them is harmless; the point of these checks
167- // during interning is to justify why we intern the *new* allocations immutably,
168- // so we can completely ignore existing allocations. We also don't need to add
169- // this to the todo list, since after all it is already interned.
170- continue ;
171- }
172- // Found a mutable pointer inside a const where inner allocations should be
173- // immutable. We exclude promoteds from this, since things like `&mut []` and
174- // `&None::<Cell<i32>>` lead to promotion that can produce mutable pointers. We rely
175- // on the promotion analysis not screwing up to ensure that it is sound to intern
176- // promoteds as immutable.
177- found_bad_mutable_pointer = true ;
178- }
179- // We always intern with `inner_mutability`, and furthermore we ensured above that if
180- // that is "immutable", then there are *no* mutable pointers anywhere in the newly
181- // interned memory -- justifying that we can indeed intern immutably. However this also
182- // means we can *not* easily intern immutably here if `prov.immutable()` is true and
183- // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and
184- // we'd have to somehow check that they are *all* immutable before deciding that this
185- // allocation can be made immutable. In the future we could consider analyzing all
186- // pointers before deciding which allocations can be made immutable; but for now we are
187- // okay with losing some potential for immutability here. This can anyway only affect
188- // `static mut`.
189- todo. push ( ( alloc_id, inner_mutability) ) ;
190- }
188+ } ) ?) ;
191189 }
192190 if found_bad_mutable_pointer {
193191 return Err ( ecx
0 commit comments