Skip to content

Commit 3c448ce

Browse files
committed
Fix misoptimization of multi-return asm
See: <rust-lang/rfcs#2625>
1 parent cb72377 commit 3c448ce

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#![cfg_attr(feature = "unstable-asm-goto", feature(asm_goto))]
2121
#![cfg_attr(feature = "unstable-asm-goto", feature(asm_goto_with_outputs))]
2222
#![cfg_attr(not(test), no_std)]
23+
use core::hint::black_box;
2324
use core::marker::PhantomData;
2425
use core::mem::MaybeUninit;
2526
use core::num::NonZero;
@@ -137,6 +138,16 @@ where
137138
let ptr = buf.as_mut_ptr();
138139
let mut val: usize;
139140

141+
// Show the optimizer that `ordinary` may be called in both ordinary and landing paths.
142+
// So it cannot assume that variables that are captured by `ordinary` are unchanged in the
143+
// lander path -- they must be reloaded.
144+
// This fixes <https://github.com/rust-lang/rfcs/issues/2625>.
145+
if size_of::<F>() == 0 {
146+
// F must not mutate local states because it captures nothing.
147+
} else {
148+
black_box(&ordinary);
149+
}
150+
140151
#[cfg(feature = "unstable-asm-goto")]
141152
unsafe {
142153
set_jump_raw!(val, ptr, {

tests/smoke.rs

+26
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,29 @@ fn smoke() {
2828
);
2929
assert_eq!(ret, 4242);
3030
}
31+
32+
#[test]
33+
fn issue2625() {
34+
#[inline(never)]
35+
fn foo() -> (usize, usize) {
36+
let mut x = 42usize;
37+
let y = JumpPoint::set_jump(
38+
|jp| {
39+
// Step 0: setjmp returns 0
40+
// Step 1: x is modified
41+
x = 13;
42+
// Step 2: jumps to Step 0 returning 1
43+
unsafe { jp.long_jump(NonZero::new(1).unwrap()) };
44+
},
45+
|y| {
46+
// Step 3: when setjmp returns 1 x has always been
47+
// modified to be == 13 so this should always return 13:
48+
y.get()
49+
},
50+
);
51+
// The optimizer must not assume `x` is unchanged in the long_jump lander path.
52+
(x, y)
53+
}
54+
55+
assert_eq!(foo(), (13, 1));
56+
}

0 commit comments

Comments
 (0)