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-22 09:22:02 +0200
committerRalf Jung <post@ralfj.de>2025-08-22 10:21:33 +0200
commit78bdd86c676a4e08849677c351591db3564d87e8 (patch)
treef8e5c85d1bafc44c868995ab15db2199b0c9315e /compiler/rustc_const_eval
parentd127901d940d96209fd2ae8ff6769ad2788099fb (diff)
downloadrust-78bdd86c676a4e08849677c351591db3564d87e8.tar.gz
rust-78bdd86c676a4e08849677c351591db3564d87e8.zip
miri: also detect aliasing of in-place argument and return place
Diffstat (limited to 'compiler/rustc_const_eval')
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs23
1 files changed, 16 insertions, 7 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 084d45cf2cb..23d362de308 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -2,6 +2,8 @@
 //!
 //! The main entry point is the `step` method.
 
+use std::iter;
+
 use either::Either;
 use rustc_abi::{FIRST_VARIANT, FieldIdx};
 use rustc_data_structures::fx::FxHashSet;
@@ -426,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         terminator: &mir::Terminator<'tcx>,
         func: &mir::Operand<'tcx>,
         args: &[Spanned<mir::Operand<'tcx>>],
+        dest: &mir::Place<'tcx>,
     ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
         let func = self.eval_operand(func, None)?;
 
@@ -435,14 +438,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // protection, but then we'd force *a lot* of arguments into memory. So we do some syntactic
         // pre-processing here where if all `move` arguments are syntactically distinct local
         // variables (and none is indirect), we can skip the in-memory forcing.
+        // We have to include `dest` in that list so that we can detect aliasing of an in-place
+        // argument with the return place.
         let move_definitely_disjoint = 'move_definitely_disjoint: {
             let mut previous_locals = FxHashSet::<mir::Local>::default();
-            for arg in args {
-                let mir::Operand::Move(place) = arg.node else {
-                    continue; // we can skip non-`Move` arguments.
-                };
+            for place in args
+                .iter()
+                .filter_map(|a| {
+                    // We only have to care about `Move` arguments.
+                    if let mir::Operand::Move(place) = &a.node { Some(place) } else { None }
+                })
+                .chain(iter::once(dest))
+            {
                 if place.is_indirect_first_projection() {
-                    // An indirect `Move` argument could alias with anything else...
+                    // An indirect in-place argument could alias with anything else...
                     break 'move_definitely_disjoint false;
                 }
                 if !previous_locals.insert(place.local) {
@@ -544,7 +553,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let old_loc = self.frame().loc;
 
                 let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
-                    self.eval_callee_and_args(terminator, func, args)?;
+                    self.eval_callee_and_args(terminator, func, args, &destination)?;
 
                 let destination = self.eval_place(destination)?;
                 self.init_fn_call(
@@ -567,7 +576,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let old_frame_idx = self.frame_idx();
 
                 let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
-                    self.eval_callee_and_args(terminator, func, args)?;
+                    self.eval_callee_and_args(terminator, func, args, &mir::Place::return_place())?;
 
                 self.init_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;