about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs41
1 files changed, 30 insertions, 11 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 808e7db5ae3..b243f07edff 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -173,17 +173,41 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         //
         // As an optimization, however, if the allocation does not contain any pointers: we don't
         // need to do the walk. It can be costly for big arrays for example (e.g. issue #93215).
+        let is_walk_needed = |mplace: &MPlaceTy<'tcx>| -> InterpResult<'tcx, bool> {
+            // ZSTs cannot contain pointers, we can avoid the interning walk.
+            if mplace.layout.is_zst() {
+                return Ok(false);
+            }
+
+            // Now, check whether this alloc contains reference types (as relocations).
+
+            // FIXME(lqd): checking the size and alignment could be expensive here, only do the
+            // following for the potentially bigger aggregates like arrays and slices.
+            let Some((size, align)) = self.ecx.size_and_align_of_mplace(&mplace)? else {
+                // We do the walk if we can't determine the size of the mplace: we may be dealing
+                // with extern types here in the future.
+                return Ok(true);
+            };
 
-        let Some((size, align)) = self.ecx.size_and_align_of_mplace(&mplace)? else {
-            // We could be dealing with an extern type here in the future, so we do the regular
+            // If there are no refs or relocations in this allocation, we can avoid the interning
             // walk.
-            return self.walk_aggregate(mplace, fields);
+            if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)?
+                && !alloc.has_relocations() {
+                return Ok(false);
+            }
+
+            // In the general case, we do the walk.
+            Ok(true)
         };
 
-        let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)? else {
-            // ZSTs cannot contain pointers, so we can skip them.
+        // If this allocation contains no references to intern, we avoid the potentially costly
+        // walk.
+        //
+        // We can do this before the checks for interior mutability below, because only references
+        // are relevant in that situation, and we're checking if there are any here.
+        if !is_walk_needed(mplace)? {
             return Ok(());
-        };
+        }
 
         if let Some(def) = mplace.layout.ty.ty_adt_def() {
             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
             }
         }
 
-        if !alloc.has_relocations() {
-            // There are no refs or relocations in this allocation, we can skip the interning walk.
-            return Ok(());
-        }
-
         self.walk_aggregate(mplace, fields)
     }