@@ -874,23 +874,27 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
874
874
// Either Acquire | AcqRel | SeqCst
875
875
clocks. apply_acquire_fence ( ) ;
876
876
}
877
- if atomic != AtomicFenceOrd :: Acquire {
878
- // Either Release | AcqRel | SeqCst
879
- clocks. apply_release_fence ( ) ;
880
- }
881
877
if atomic == AtomicFenceOrd :: SeqCst {
882
878
// Behave like an RMW on the global fence location. This takes full care of
883
879
// all the SC fence requirements, including C++17 §32.4 [atomics.order]
884
880
// paragraph 6 (which would limit what future reads can see). It also rules
885
881
// out many legal behaviors, but we don't currently have a model that would
886
882
// 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>.
887
885
let mut sc_fence_clock = data_race. last_sc_fence . borrow_mut ( ) ;
888
886
sc_fence_clock. join ( & clocks. clock ) ;
889
887
clocks. clock . join ( & sc_fence_clock) ;
890
888
// Also establish some sort of order with the last SC write that happened, globally
891
889
// (but this is only respected by future reads).
892
890
clocks. write_seqcst . join ( & data_race. last_sc_write_per_thread . borrow ( ) ) ;
893
891
}
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
+ }
894
898
895
899
// Increment timestamp in case of release semantics.
896
900
interp_ok ( atomic != AtomicFenceOrd :: Acquire )
0 commit comments