@@ -173,17 +173,41 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
173
173
//
174
174
// As an optimization, however, if the allocation does not contain any pointers: we don't
175
175
// need to do the walk. It can be costly for big arrays for example (e.g. issue #93215).
176
+ let is_walk_needed = |mplace : & MPlaceTy < ' tcx > | -> InterpResult < ' tcx , bool > {
177
+ // ZSTs cannot contain pointers, we can avoid the interning walk.
178
+ if mplace. layout . is_zst ( ) {
179
+ return Ok ( false ) ;
180
+ }
181
+
182
+ // Now, check whether this alloc contains reference types (as relocations).
183
+
184
+ // FIXME(lqd): checking the size and alignment could be expensive here, only do the
185
+ // following for the potentially bigger aggregates like arrays and slices.
186
+ let Some ( ( size, align) ) = self . ecx . size_and_align_of_mplace ( & mplace) ? else {
187
+ // We do the walk if we can't determine the size of the mplace: we may be dealing
188
+ // with extern types here in the future.
189
+ return Ok ( true ) ;
190
+ } ;
176
191
177
- let Some ( ( size, align) ) = self . ecx . size_and_align_of_mplace ( & mplace) ? else {
178
- // We could be dealing with an extern type here in the future, so we do the regular
192
+ // If there are no refs or relocations in this allocation, we can avoid the interning
179
193
// walk.
180
- return self . walk_aggregate ( mplace, fields) ;
194
+ if let Some ( alloc) = self . ecx . get_ptr_alloc ( mplace. ptr , size, align) ?
195
+ && !alloc. has_relocations ( ) {
196
+ return Ok ( false ) ;
197
+ }
198
+
199
+ // In the general case, we do the walk.
200
+ Ok ( true )
181
201
} ;
182
202
183
- let Some ( alloc) = self . ecx . get_ptr_alloc ( mplace. ptr , size, align) ? else {
184
- // ZSTs cannot contain pointers, so we can skip them.
203
+ // If this allocation contains no references to intern, we avoid the potentially costly
204
+ // walk.
205
+ //
206
+ // We can do this before the checks for interior mutability below, because only references
207
+ // are relevant in that situation, and we're checking if there are any here.
208
+ if !is_walk_needed ( mplace) ? {
185
209
return Ok ( ( ) ) ;
186
- } ;
210
+ }
187
211
188
212
if let Some ( def) = mplace. layout . ty . ty_adt_def ( ) {
189
213
if Some ( def. did ( ) ) == self . ecx . tcx . lang_items ( ) . unsafe_cell_type ( ) {
@@ -198,11 +222,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
198
222
}
199
223
}
200
224
201
- if !alloc. has_relocations ( ) {
202
- // There are no refs or relocations in this allocation, we can skip the interning walk.
203
- return Ok ( ( ) ) ;
204
- }
205
-
206
225
self . walk_aggregate ( mplace, fields)
207
226
}
208
227
0 commit comments