@@ -874,23 +874,27 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
874874 // Either Acquire | AcqRel | SeqCst
875875 clocks. apply_acquire_fence ( ) ;
876876 }
877- if atomic != AtomicFenceOrd :: Acquire {
878- // Either Release | AcqRel | SeqCst
879- clocks. apply_release_fence ( ) ;
880- }
881877 if atomic == AtomicFenceOrd :: SeqCst {
882878 // Behave like an RMW on the global fence location. This takes full care of
883879 // all the SC fence requirements, including C++17 §32.4 [atomics.order]
884880 // paragraph 6 (which would limit what future reads can see). It also rules
885881 // out many legal behaviors, but we don't currently have a model that would
886882 // be more precise.
883+ // Also see the second bullet on page 10 of
884+ // <https://www.cs.tau.ac.il/~orilahav/papers/popl21_robustness.pdf>.
887885 let mut sc_fence_clock = data_race. last_sc_fence . borrow_mut ( ) ;
888886 sc_fence_clock. join ( & clocks. clock ) ;
889887 clocks. clock . join ( & sc_fence_clock) ;
890888 // Also establish some sort of order with the last SC write that happened, globally
891889 // (but this is only respected by future reads).
892890 clocks. write_seqcst . join ( & data_race. last_sc_write_per_thread . borrow ( ) ) ;
893891 }
892+ // The release fence is last, since both of the above could alter our clock,
893+ // which should be part of what is being released.
894+ if atomic != AtomicFenceOrd :: Acquire {
895+ // Either Release | AcqRel | SeqCst
896+ clocks. apply_release_fence ( ) ;
897+ }
894898
895899 // Increment timestamp in case of release semantics.
896900 interp_ok ( atomic != AtomicFenceOrd :: Acquire )
0 commit comments