authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-03-10 22:46:19+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-03-10 22:54:47+02:00
logee5b00a8b90ef375d0cd4432d31e3a4ed0b6f632
treec775663438485092fca336a68a5bcbbc047de818
parent8dc188ebe06b5b78dcead521561858fc27e25204
signaturelock-open Commit is signed but in an unrecognized format.

use atomic bools in std lib


7 files changed, 83 insertions(+), 79 deletions(-)

lib/std/atomic/queue.zig+9-11
......@@ -1,7 +1,5 @@
11const std = @import("../std.zig");
22const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;
4const AtomicRmwOp = builtin.AtomicRmwOp;
53const assert = std.debug.assert;
64const expect = std.testing.expect;
75
......@@ -149,7 +147,7 @@ const Context = struct {
149147 put_sum: isize,
150148 get_sum: isize,
151149 get_count: usize,
152 puts_done: u8, // TODO make this a bool
150 puts_done: bool,
153151};
154152
155153// TODO add lazy evaluated build options and then put puts_per_thread behind
......@@ -173,7 +171,7 @@ test "std.atomic.Queue" {
173171 .queue = &queue,
174172 .put_sum = 0,
175173 .get_sum = 0,
176 .puts_done = 0,
174 .puts_done = false,
177175 .get_count = 0,
178176 };
179177
......@@ -186,7 +184,7 @@ test "std.atomic.Queue" {
186184 }
187185 }
188186 expect(!context.queue.isEmpty());
189 context.puts_done = 1;
187 context.puts_done = true;
190188 {
191189 var i: usize = 0;
192190 while (i < put_thread_count) : (i += 1) {
......@@ -208,7 +206,7 @@ test "std.atomic.Queue" {
208206
209207 for (putters) |t|
210208 t.wait();
211 @atomicStore(u8, &context.puts_done, 1, AtomicOrder.SeqCst);
209 @atomicStore(bool, &context.puts_done, true, .SeqCst);
212210 for (getters) |t|
213211 t.wait();
214212
......@@ -235,25 +233,25 @@ fn startPuts(ctx: *Context) u8 {
235233 std.time.sleep(1); // let the os scheduler be our fuzz
236234 const x = @bitCast(i32, r.random.scalar(u32));
237235 const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
238 node.* = Queue(i32).Node{
236 node.* = .{
239237 .prev = undefined,
240238 .next = undefined,
241239 .data = x,
242240 };
243241 ctx.queue.put(node);
244 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
242 _ = @atomicRmw(isize, &ctx.put_sum, .Add, x, .SeqCst);
245243 }
246244 return 0;
247245}
248246
249247fn startGets(ctx: *Context) u8 {
250248 while (true) {
251 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
249 const last = @atomicLoad(bool, &ctx.puts_done, .SeqCst);
252250
253251 while (ctx.queue.get()) |node| {
254252 std.time.sleep(1); // let the os scheduler be our fuzz
255 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
256 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
253 _ = @atomicRmw(isize, &ctx.get_sum, .Add, node.data, .SeqCst);
254 _ = @atomicRmw(usize, &ctx.get_count, .Add, 1, .SeqCst);
257255 }
258256
259257 if (last) return 0;
lib/std/atomic/stack.zig+15-16
......@@ -1,6 +1,5 @@
11const assert = std.debug.assert;
22const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;
43const expect = std.testing.expect;
54
65/// Many reader, many writer, non-allocating, thread-safe
......@@ -11,7 +10,7 @@ pub fn Stack(comptime T: type) type {
1110 root: ?*Node,
1211 lock: @TypeOf(lock_init),
1312
14 const lock_init = if (builtin.single_threaded) {} else @as(u8, 0);
13 const lock_init = if (builtin.single_threaded) {} else false;
1514
1615 pub const Self = @This();
1716
......@@ -31,7 +30,7 @@ pub fn Stack(comptime T: type) type {
3130 /// being the first item in the stack, returns the other item that was there.
3231 pub fn pushFirst(self: *Self, node: *Node) ?*Node {
3332 node.next = null;
34 return @cmpxchgStrong(?*Node, &self.root, null, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst);
33 return @cmpxchgStrong(?*Node, &self.root, null, node, .SeqCst, .SeqCst);
3534 }
3635
3736 pub fn push(self: *Self, node: *Node) void {
......@@ -39,8 +38,8 @@ pub fn Stack(comptime T: type) type {
3938 node.next = self.root;
4039 self.root = node;
4140 } else {
42 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
43 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
41 while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst) != false) {}
42 defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst) == true);
4443
4544 node.next = self.root;
4645 self.root = node;
......@@ -53,8 +52,8 @@ pub fn Stack(comptime T: type) type {
5352 self.root = root.next;
5453 return root;
5554 } else {
56 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
57 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
55 while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst) != false) {}
56 defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst) == true);
5857
5958 const root = self.root orelse return null;
6059 self.root = root.next;
......@@ -63,7 +62,7 @@ pub fn Stack(comptime T: type) type {
6362 }
6463
6564 pub fn isEmpty(self: *Self) bool {
66 return @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst) == null;
65 return @atomicLoad(?*Node, &self.root, .SeqCst) == null;
6766 }
6867 };
6968}
......@@ -75,7 +74,7 @@ const Context = struct {
7574 put_sum: isize,
7675 get_sum: isize,
7776 get_count: usize,
78 puts_done: u8, // TODO make this a bool
77 puts_done: bool,
7978};
8079// TODO add lazy evaluated build options and then put puts_per_thread behind
8180// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
......@@ -98,7 +97,7 @@ test "std.atomic.stack" {
9897 .stack = &stack,
9998 .put_sum = 0,
10099 .get_sum = 0,
101 .puts_done = 0,
100 .puts_done = false,
102101 .get_count = 0,
103102 };
104103
......@@ -109,7 +108,7 @@ test "std.atomic.stack" {
109108 expect(startPuts(&context) == 0);
110109 }
111110 }
112 context.puts_done = 1;
111 context.puts_done = true;
113112 {
114113 var i: usize = 0;
115114 while (i < put_thread_count) : (i += 1) {
......@@ -128,7 +127,7 @@ test "std.atomic.stack" {
128127
129128 for (putters) |t|
130129 t.wait();
131 @atomicStore(u8, &context.puts_done, 1, AtomicOrder.SeqCst);
130 @atomicStore(bool, &context.puts_done, true, .SeqCst);
132131 for (getters) |t|
133132 t.wait();
134133 }
......@@ -158,19 +157,19 @@ fn startPuts(ctx: *Context) u8 {
158157 .data = x,
159158 };
160159 ctx.stack.push(node);
161 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
160 _ = @atomicRmw(isize, &ctx.put_sum, .Add, x, .SeqCst);
162161 }
163162 return 0;
164163}
165164
166165fn startGets(ctx: *Context) u8 {
167166 while (true) {
168 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
167 const last = @atomicLoad(bool, &ctx.puts_done, .SeqCst) == true;
169168
170169 while (ctx.stack.pop()) |node| {
171170 std.time.sleep(1); // let the os scheduler be our fuzz
172 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
173 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
171 _ = @atomicRmw(isize, &ctx.get_sum, .Add, node.data, .SeqCst);
172 _ = @atomicRmw(usize, &ctx.get_count, .Add, 1, .SeqCst);
174173 }
175174
176175 if (last) return 0;
lib/std/event/channel.zig+12-12
......@@ -14,8 +14,8 @@ pub fn Channel(comptime T: type) type {
1414 putters: std.atomic.Queue(PutNode),
1515 get_count: usize,
1616 put_count: usize,
17 dispatch_lock: u8, // TODO make this a bool
18 need_dispatch: u8, // TODO make this a bool
17 dispatch_lock: bool,
18 need_dispatch: bool,
1919
2020 // simple fixed size ring buffer
2121 buffer_nodes: []T,
......@@ -62,8 +62,8 @@ pub fn Channel(comptime T: type) type {
6262 .buffer_len = 0,
6363 .buffer_nodes = buffer,
6464 .buffer_index = 0,
65 .dispatch_lock = 0,
66 .need_dispatch = 0,
65 .dispatch_lock = false,
66 .need_dispatch = false,
6767 .getters = std.atomic.Queue(GetNode).init(),
6868 .putters = std.atomic.Queue(PutNode).init(),
6969 .or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(),
......@@ -165,15 +165,15 @@ pub fn Channel(comptime T: type) type {
165165
166166 fn dispatch(self: *SelfChannel) void {
167167 // set the "need dispatch" flag
168 @atomicStore(u8, &self.need_dispatch, 1, .SeqCst);
168 @atomicStore(bool, &self.need_dispatch, true, .SeqCst);
169169
170170 lock: while (true) {
171171 // set the lock flag
172 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 1, .SeqCst);
172 const prev_lock = @atomicRmw(bool, &self.dispatch_lock, .Xchg, true, .SeqCst);
173173 if (prev_lock != 0) return;
174174
175175 // clear the need_dispatch flag since we're about to do it
176 @atomicStore(u8, &self.need_dispatch, 0, .SeqCst);
176 @atomicStore(bool, &self.need_dispatch, false, .SeqCst);
177177
178178 while (true) {
179179 one_dispatch: {
......@@ -250,14 +250,14 @@ pub fn Channel(comptime T: type) type {
250250 }
251251
252252 // clear need-dispatch flag
253 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
254 if (need_dispatch != 0) continue;
253 const need_dispatch = @atomicRmw(bool, &self.need_dispatch, .Xchg, false, .SeqCst);
254 if (need_dispatch) continue;
255255
256 const my_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 0, .SeqCst);
257 assert(my_lock != 0);
256 const my_lock = @atomicRmw(bool, &self.dispatch_lock, .Xchg, false, .SeqCst);
257 assert(my_lock);
258258
259259 // we have to check again now that we unlocked
260 if (@atomicLoad(u8, &self.need_dispatch, .SeqCst) != 0) continue :lock;
260 if (@atomicLoad(bool, &self.need_dispatch, .SeqCst)) continue :lock;
261261
262262 return;
263263 }
lib/std/event/lock.zig+17-19
......@@ -11,9 +11,9 @@ const Loop = std.event.Loop;
1111/// Allows only one actor to hold the lock.
1212/// TODO: make this API also work in blocking I/O mode.
1313pub const Lock = struct {
14 shared_bit: u8, // TODO make this a bool
14 shared: bool,
1515 queue: Queue,
16 queue_empty_bit: u8, // TODO make this a bool
16 queue_empty: bool,
1717
1818 const Queue = std.atomic.Queue(anyframe);
1919
......@@ -31,20 +31,19 @@ pub const Lock = struct {
3131 }
3232
3333 // We need to release the lock.
34 @atomicStore(u8, &self.lock.queue_empty_bit, 1, .SeqCst);
35 @atomicStore(u8, &self.lock.shared_bit, 0, .SeqCst);
34 @atomicStore(bool, &self.lock.queue_empty, true, .SeqCst);
35 @atomicStore(bool, &self.lock.shared, false, .SeqCst);
3636
3737 // There might be a queue item. If we know the queue is empty, we can be done,
3838 // because the other actor will try to obtain the lock.
3939 // But if there's a queue item, we are the actor which must loop and attempt
4040 // to grab the lock again.
41 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
41 if (@atomicLoad(bool, &self.lock.queue_empty, .SeqCst)) {
4242 return;
4343 }
4444
4545 while (true) {
46 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 1, .SeqCst);
47 if (old_bit != 0) {
46 if (@atomicRmw(bool, &self.lock.shared, .Xchg, true, .SeqCst)) {
4847 // We did not obtain the lock. Great, the queue is someone else's problem.
4948 return;
5049 }
......@@ -56,11 +55,11 @@ pub const Lock = struct {
5655 }
5756
5857 // Release the lock again.
59 @atomicStore(u8, &self.lock.queue_empty_bit, 1, .SeqCst);
60 @atomicStore(u8, &self.lock.shared_bit, 0, .SeqCst);
58 @atomicStore(bool, &self.lock.queue_empty, true, .SeqCst);
59 @atomicStore(bool, &self.lock.shared, false, .SeqCst);
6160
6261 // Find out if we can be done.
63 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
62 if (@atomicLoad(bool, &self.lock.queue_empty, .SeqCst)) {
6463 return;
6564 }
6665 }
......@@ -69,24 +68,24 @@ pub const Lock = struct {
6968
7069 pub fn init() Lock {
7170 return Lock{
72 .shared_bit = 0,
71 .shared = false,
7372 .queue = Queue.init(),
74 .queue_empty_bit = 1,
73 .queue_empty = true,
7574 };
7675 }
7776
7877 pub fn initLocked() Lock {
7978 return Lock{
80 .shared_bit = 1,
79 .shared = true,
8180 .queue = Queue.init(),
82 .queue_empty_bit = 1,
81 .queue_empty = true,
8382 };
8483 }
8584
8685 /// Must be called when not locked. Not thread safe.
8786 /// All calls to acquire() and release() must complete before calling deinit().
8887 pub fn deinit(self: *Lock) void {
89 assert(self.shared_bit == 0);
88 assert(!self.shared);
9089 while (self.queue.get()) |node| resume node.data;
9190 }
9291
......@@ -99,12 +98,11 @@ pub const Lock = struct {
9998
10099 // At this point, we are in the queue, so we might have already been resumed.
101100
102 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor
101 // We set this bit so that later we can rely on the fact, that if queue_empty == true, some actor
103102 // will attempt to grab the lock.
104 @atomicStore(u8, &self.queue_empty_bit, 0, .SeqCst);
103 @atomicStore(bool, &self.queue_empty, false, .SeqCst);
105104
106 const old_bit = @atomicRmw(u8, &self.shared_bit, .Xchg, 1, .SeqCst);
107 if (old_bit == 0) {
105 if (!@atomicRmw(bool, &self.shared, .Xchg, true, .SeqCst)) {
108106 if (self.queue.get()) |node| {
109107 // Whether this node is us or someone else, we tail resume it.
110108 resume node.data;
lib/std/event/rwlock.zig+16-16
......@@ -16,8 +16,8 @@ pub const RwLock = struct {
1616 shared_state: State,
1717 writer_queue: Queue,
1818 reader_queue: Queue,
19 writer_queue_empty_bit: u8, // TODO make this a bool
20 reader_queue_empty_bit: u8, // TODO make this a bool
19 writer_queue_empty: bool,
20 reader_queue_empty: bool,
2121 reader_lock_count: usize,
2222
2323 const State = enum(u8) {
......@@ -40,7 +40,7 @@ pub const RwLock = struct {
4040 return;
4141 }
4242
43 @atomicStore(u8, &self.lock.reader_queue_empty_bit, 1, .SeqCst);
43 @atomicStore(bool, &self.lock.reader_queue_empty, true, .SeqCst);
4444 if (@cmpxchgStrong(State, &self.lock.shared_state, .ReadLock, .Unlocked, .SeqCst, .SeqCst) != null) {
4545 // Didn't unlock. Someone else's problem.
4646 return;
......@@ -62,7 +62,7 @@ pub const RwLock = struct {
6262 }
6363
6464 // We need to release the write lock. Check if any readers are waiting to grab the lock.
65 if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, .SeqCst) == 0) {
65 if (!@atomicLoad(bool, &self.lock.reader_queue_empty, .SeqCst)) {
6666 // Switch to a read lock.
6767 @atomicStore(State, &self.lock.shared_state, .ReadLock, .SeqCst);
6868 while (self.lock.reader_queue.get()) |node| {
......@@ -71,7 +71,7 @@ pub const RwLock = struct {
7171 return;
7272 }
7373
74 @atomicStore(u8, &self.lock.writer_queue_empty_bit, 1, .SeqCst);
74 @atomicStore(bool, &self.lock.writer_queue_empty, true, .SeqCst);
7575 @atomicStore(State, &self.lock.shared_state, .Unlocked, .SeqCst);
7676
7777 self.lock.commonPostUnlock();
......@@ -79,12 +79,12 @@ pub const RwLock = struct {
7979 };
8080
8181 pub fn init() RwLock {
82 return RwLock{
82 return .{
8383 .shared_state = .Unlocked,
8484 .writer_queue = Queue.init(),
85 .writer_queue_empty_bit = 1,
85 .writer_queue_empty = true,
8686 .reader_queue = Queue.init(),
87 .reader_queue_empty_bit = 1,
87 .reader_queue_empty = true,
8888 .reader_lock_count = 0,
8989 };
9090 }
......@@ -111,9 +111,9 @@ pub const RwLock = struct {
111111
112112 // At this point, we are in the reader_queue, so we might have already been resumed.
113113
114 // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,
114 // We set this bit so that later we can rely on the fact, that if reader_queue_empty == true,
115115 // some actor will attempt to grab the lock.
116 @atomicStore(u8, &self.reader_queue_empty_bit, 0, .SeqCst);
116 @atomicStore(bool, &self.reader_queue_empty, false, .SeqCst);
117117
118118 // Here we don't care if we are the one to do the locking or if it was already locked for reading.
119119 const have_read_lock = if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .ReadLock, .SeqCst, .SeqCst)) |old_state| old_state == .ReadLock else true;
......@@ -142,9 +142,9 @@ pub const RwLock = struct {
142142
143143 // At this point, we are in the writer_queue, so we might have already been resumed.
144144
145 // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,
145 // We set this bit so that later we can rely on the fact, that if writer_queue_empty == true,
146146 // some actor will attempt to grab the lock.
147 @atomicStore(u8, &self.writer_queue_empty_bit, 0, .SeqCst);
147 @atomicStore(bool, &self.writer_queue_empty, false, .SeqCst);
148148
149149 // Here we must be the one to acquire the write lock. It cannot already be locked.
150150 if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .WriteLock, .SeqCst, .SeqCst) == null) {
......@@ -165,7 +165,7 @@ pub const RwLock = struct {
165165 // obtain the lock.
166166 // But if there's a writer_queue item or a reader_queue item,
167167 // we are the actor which must loop and attempt to grab the lock again.
168 if (@atomicLoad(u8, &self.writer_queue_empty_bit, .SeqCst) == 0) {
168 if (!@atomicLoad(bool, &self.writer_queue_empty, .SeqCst)) {
169169 if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .WriteLock, .SeqCst, .SeqCst) != null) {
170170 // We did not obtain the lock. Great, the queues are someone else's problem.
171171 return;
......@@ -176,12 +176,12 @@ pub const RwLock = struct {
176176 return;
177177 }
178178 // Release the lock again.
179 @atomicStore(u8, &self.writer_queue_empty_bit, 1, .SeqCst);
179 @atomicStore(bool, &self.writer_queue_empty, true, .SeqCst);
180180 @atomicStore(State, &self.shared_state, .Unlocked, .SeqCst);
181181 continue;
182182 }
183183
184 if (@atomicLoad(u8, &self.reader_queue_empty_bit, .SeqCst) == 0) {
184 if (!@atomicLoad(bool, &self.reader_queue_empty, .SeqCst)) {
185185 if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .ReadLock, .SeqCst, .SeqCst) != null) {
186186 // We did not obtain the lock. Great, the queues are someone else's problem.
187187 return;
......@@ -195,7 +195,7 @@ pub const RwLock = struct {
195195 return;
196196 }
197197 // Release the lock again.
198 @atomicStore(u8, &self.reader_queue_empty_bit, 1, .SeqCst);
198 @atomicStore(bool, &self.reader_queue_empty, true, .SeqCst);
199199 if (@cmpxchgStrong(State, &self.shared_state, .ReadLock, .Unlocked, .SeqCst, .SeqCst) != null) {
200200 // Didn't unlock. Someone else's problem.
201201 return;
src/ir.cpp+3-3
......@@ -28397,15 +28397,15 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
2839728397
2839828398 if (operand_type->id == ZigTypeIdEnum && op != AtomicRmwOp_xchg) {
2839928399 ir_add_error(ira, &instruction->op->base,
28400 buf_sprintf("@atomicRmw on enum only works with .Xchg"));
28400 buf_sprintf("@atomicRmw with enum only allowed with .Xchg"));
2840128401 return ira->codegen->invalid_inst_gen;
2840228402 } else if (operand_type->id == ZigTypeIdBool && op != AtomicRmwOp_xchg) {
2840328403 ir_add_error(ira, &instruction->op->base,
28404 buf_sprintf("@atomicRmw on bool only works with .Xchg"));
28404 buf_sprintf("@atomicRmw with bool only allowed with .Xchg"));
2840528405 return ira->codegen->invalid_inst_gen;
2840628406 } else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) {
2840728407 ir_add_error(ira, &instruction->op->base,
28408 buf_sprintf("@atomicRmw with float only works with .Xchg, .Add and .Sub"));
28408 buf_sprintf("@atomicRmw with float only allowed with .Xchg, .Add and .Sub"));
2840928409 return ira->codegen->invalid_inst_gen;
2841028410 }
2841128411
test/compile_errors.zig+11-2
......@@ -2,6 +2,15 @@ const tests = @import("tests.zig");
22const std = @import("std");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add("atomicrmw with bool op not .Xchg",
6 \\export fn entry() void {
7 \\ var x = false;
8 \\ _ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
9 \\}
10 , &[_][]const u8{
11 "tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg",
12 });
13
514 cases.addTest("combination of noasync and async",
615 \\export fn entry() void {
716 \\ noasync {
......@@ -325,7 +334,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
325334 \\ _ = @atomicRmw(f32, &x, .And, 2, .SeqCst);
326335 \\}
327336 , &[_][]const u8{
328 "tmp.zig:3:29: error: @atomicRmw with float only works with .Xchg, .Add and .Sub",
337 "tmp.zig:3:29: error: @atomicRmw with float only allowed with .Xchg, .Add and .Sub",
329338 });
330339
331340 cases.add("intToPtr with misaligned address",
......@@ -542,7 +551,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
542551 \\ _ = @atomicRmw(E, &x, .Add, .b, .SeqCst);
543552 \\}
544553 , &[_][]const u8{
545 "tmp.zig:9:27: error: @atomicRmw on enum only works with .Xchg",
554 "tmp.zig:9:27: error: @atomicRmw with enum only allowed with .Xchg",
546555 });
547556
548557 cases.add("disallow coercion from non-null-terminated pointer to null-terminated pointer",