Skip to content

Commit 752a910

Browse files
committed
MIR Call terminator: evaluate destination place before arguments
1 parent 44860d3 commit 752a910

2 files changed

Lines changed: 10 additions & 6 deletions

File tree

compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,16 +541,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
541541
let old_stack = self.frame_idx();
542542
let old_loc = self.frame().loc;
543543

544+
// Evaluation order consistent with assignment: destination first.
545+
let dest_place = self.eval_place(destination)?;
544546
let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
545547
self.eval_callee_and_args(terminator, func, args, &destination)?;
546548

547-
let destination = self.eval_place(destination)?;
548549
self.init_fn_call(
549550
callee,
550551
(fn_sig.abi(), fn_abi),
551552
&args,
552553
with_caller_location,
553-
&destination,
554+
&dest_place,
554555
target,
555556
if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
556557
)?;

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,9 @@ pub enum StatementKind<'tcx> {
306306
/// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except
307307
/// without the possibility of dropping the previous value (that must be done separately, if at
308308
/// all). The *exact* way this works is undecided. It probably does something like evaluating
309-
/// the LHS to a place and the RHS to a value, and then storing the value to the place. Various
310-
/// parts of this may do type specific things that are more complicated than simply copying
311-
/// bytes. In particular, the assignment will typically erase the contents of padding,
309+
/// the LHS to a place, then the RHS to a value, and then storing the value to the place.
310+
/// Various parts of this may do type specific things that are more complicated than simply
311+
/// copying bytes. In particular, the assignment will typically erase the contents of padding,
312312
/// erase provenance from non-pointer types, and implicitly "retag" all references and boxes
313313
/// that it copies, meaning that the resulting value is not an exact duplicate for all intents
314314
/// and purposes of the original value.
@@ -796,6 +796,9 @@ pub enum TerminatorKind<'tcx> {
796796
/// operands not aliasing the return place. It is unclear how this is justified in MIR, see
797797
/// [#71117].
798798
///
799+
/// The evaluation order is currently "first compute destination place, then `func` operand,
800+
/// then the arguments in left-to-right order".
801+
///
799802
/// [#71117]: https://github.com/rust-lang/rust/issues/71117
800803
Call {
801804
/// The function that’s being called.
@@ -1494,7 +1497,7 @@ pub enum CastKind {
14941497
/// but running a transmute between differently-sized types is UB.
14951498
Transmute,
14961499

1497-
/// A `Subtype` cast is applied to any `StatementKind::Assign` where
1500+
/// A `Subtype` cast is applied to any [`StatementKind::Assign`] where
14981501
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
14991502
/// explicit during optimizations and codegen.
15001503
///

0 commit comments

Comments
 (0)