@@ -35,7 +35,7 @@ fn spin_until(loc: &AtomicUsize, val: usize) -> usize {
35
35
36
36
/// Check that the function produces the intended set of outcomes.
37
37
#[ track_caller]
38
- fn check_all_outcomes < T : Eq + std:: hash:: Hash + std:: fmt:: Display > (
38
+ fn check_all_outcomes < T : Eq + std:: hash:: Hash + std:: fmt:: Debug > (
39
39
expected : impl IntoIterator < Item = T > ,
40
40
generate : impl Fn ( ) -> T ,
41
41
) {
@@ -47,7 +47,7 @@ fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Display>(
47
47
let tries = expected. len ( ) * 12 ;
48
48
for i in 0 ..tries {
49
49
let val = generate ( ) ;
50
- assert ! ( expected. contains( & val) , "got an unexpected value: {val}" ) ;
50
+ assert ! ( expected. contains( & val) , "got an unexpected value: {val:? }" ) ;
51
51
seen. insert ( val) ;
52
52
if i > tries / 2 && expected. len ( ) == seen. len ( ) {
53
53
// We saw everything and we did quite a few tries, let's avoid wasting time.
@@ -57,7 +57,7 @@ fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Display>(
57
57
// Let's see if we saw them all.
58
58
for val in expected {
59
59
if !seen. contains ( & val) {
60
- panic ! ( "did not get value that should be possible: {val}" ) ;
60
+ panic ! ( "did not get value that should be possible: {val:? }" ) ;
61
61
}
62
62
}
63
63
}
@@ -163,10 +163,46 @@ fn faa_replaced_by_load() {
163
163
} ) ;
164
164
}
165
165
166
+ /// Checking that the weaker release sequence example from
167
+ /// <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r0.html> can actually produce the
168
+ /// new behavior (`Some(0)` in our version).
169
+ fn weaker_release_sequences ( ) {
170
+ check_all_outcomes ( [ None , Some ( 0 ) , Some ( 1 ) ] , || {
171
+ let x = static_atomic ( 0 ) ;
172
+ let y = static_atomic ( 0 ) ;
173
+
174
+ let t1 = spawn ( move || {
175
+ x. store ( 2 , Relaxed ) ;
176
+ } ) ;
177
+ let t2 = spawn ( move || {
178
+ y. store ( 1 , Relaxed ) ;
179
+ x. store ( 1 , Release ) ;
180
+ x. store ( 3 , Relaxed ) ;
181
+ } ) ;
182
+ let t3 = spawn ( move || {
183
+ if x. load ( Acquire ) == 3 {
184
+ // In C++11, if we read the 3 here, and if the store of 1 was just before the store
185
+ // of 3 in mo order (which it is because we fix the schedule), this forms a release
186
+ // sequence, meaning we acquire the release store of 1, and we can thus never see
187
+ // the value 0.
188
+ // In C++20, this is no longer a release sequence, so 0 can now be observed.
189
+ Some ( y. load ( Relaxed ) )
190
+ } else {
191
+ None
192
+ }
193
+ } ) ;
194
+
195
+ t1. join ( ) . unwrap ( ) ;
196
+ t2. join ( ) . unwrap ( ) ;
197
+ t3. join ( ) . unwrap ( )
198
+ } ) ;
199
+ }
200
+
166
201
pub fn main ( ) {
167
202
relaxed ( ) ;
168
203
seq_cst ( ) ;
169
204
initialization_write ( false ) ;
170
205
initialization_write ( true ) ;
171
206
faa_replaced_by_load ( ) ;
207
+ weaker_release_sequences ( ) ;
172
208
}
0 commit comments