about summary refs log tree commit diff
path: root/compiler/rustc_const_eval
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-08-18 17:22:02 +0200
committerRalf Jung <post@ralfj.de>2025-08-18 19:45:29 +0200
commitece1397e3ff40e7f8a411981844a8214659da970 (patch)
tree95dc997256c1402829aed816b00c4a8e6de6e5ba /compiler/rustc_const_eval
parent2c1ac85679678dfe5cce7ea8037735b0349ceaf3 (diff)
downloadrust-ece1397e3ff40e7f8a411981844a8214659da970.tar.gz
rust-ece1397e3ff40e7f8a411981844a8214659da970.zip
interpret: fix in-place return place semantics when the return place expression is a local variable
Diffstat (limited to 'compiler/rustc_const_eval')
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs1
3 files changed, 16 insertions, 3 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index b1cc0cc2878..7b3c80538ca 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -27,8 +27,9 @@ use crate::{enter_trace_span, fluent_generated as fluent};
 pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
     /// Pass a copy of the given operand.
     Copy(OpTy<'tcx, Prov>),
-    /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
-    /// make the place inaccessible for the duration of the function call.
+    /// Allow for the argument to be passed in-place: destroy the value originally stored at that
+    /// place and make the place inaccessible for the duration of the function call. This *must* be
+    /// an in-memory place so that we can do the proper alias checks.
     InPlace(MPlaceTy<'tcx, Prov>),
 }
 
@@ -379,6 +380,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
 
+        // *Before* pushing the new frame, determine whether the return destination is in memory.
+        // Need to use `place_to_op` to be *sure* we get the mplace if there is one.
+        let destination_mplace = self.place_to_op(destination)?.as_mplace_or_imm().left();
+
+        // Push the "raw" frame -- this leaves locals uninitialized.
         self.push_stack_frame_raw(instance, body, destination, cont)?;
 
         // If an error is raised here, pop the frame again to get an accurate backtrace.
@@ -496,7 +502,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
             // Protect return place for in-place return value passing.
             // We only need to protect anything if this is actually an in-memory place.
-            if let Left(mplace) = destination.as_mplace_or_local() {
+            if let Some(mplace) = destination_mplace {
                 M::protect_in_place_function_argument(self, &mplace)?;
             }
 
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 6ff50dc700f..921fa8677fe 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -234,6 +234,12 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> {
     }
 
     /// A place is either an mplace or some local.
+    ///
+    /// Note that the return value can be different even for logically identical places!
+    /// Specifically, if a local is stored in-memory, this may return `Local` or `MPlaceTy`
+    /// depending on how the place was constructed. In other words, seeing `Local` here does *not*
+    /// imply that this place does not point to memory. Every caller must therefore always handle
+    /// both cases.
     #[inline(always)]
     pub fn as_mplace_or_local(
         &self,
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 76e470b69dc..36251f774c6 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -415,6 +415,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         // caller directly access this local!
                         // This is also crucial for tail calls, where we want the `FnArg` to
                         // stay valid when the old stack frame gets popped.
+                        // FIXME: How can this be right for aliasing arguments?
                         FnArg::Copy(op)
                     }
                 }