Skip to content

Commit ba49062

Browse files
authored
[Clang][AST] Fix printing for atomic_test_and_set and atomic_clear (#159712)
#121943 rewrote `__atomic_test_and_set` and `__atomic_clear` to be lowered through AtomicExpr StmtPrinter::VisitAtomicExpr still treated them like other atomic builtins with a Val1 operand. This led to incorrect pretty-printing when dumping the AST. Skip Val1 for these two builtins like atomic loads.
1 parent 188c7ed commit ba49062

File tree

4 files changed

+117
-5
lines changed

4 files changed

+117
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ AST Dumping Potentially Breaking Changes
114114
----------------------------------------
115115
- How nested name specifiers are dumped and printed changes, keeping track of clang AST changes.
116116

117+
- Pretty-printing of atomic builtins ``__atomic_test_and_set`` and ``__atomic_clear`` in ``-ast-print`` output.
118+
These previously displayed an extra ``<null expr>`` argument, e.g.:
119+
120+
``__atomic_test_and_set(p, <null expr>, 0)``
121+
122+
Now they are printed as:
123+
124+
``__atomic_test_and_set(p, 0)``
125+
117126
Clang Frontend Potentially Breaking Changes
118127
-------------------------------------------
119128
- Members of anonymous unions/structs are now injected as ``IndirectFieldDecl``

clang/include/clang/AST/Expr.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6908,6 +6908,21 @@ class AtomicExpr : public Expr {
69086908
getOp() == AO__scoped_atomic_compare_exchange_n;
69096909
}
69106910

6911+
bool hasVal1Operand() const {
6912+
switch (getOp()) {
6913+
case AO__atomic_load_n:
6914+
case AO__scoped_atomic_load_n:
6915+
case AO__c11_atomic_load:
6916+
case AO__opencl_atomic_load:
6917+
case AO__hip_atomic_load:
6918+
case AO__atomic_test_and_set:
6919+
case AO__atomic_clear:
6920+
return false;
6921+
default:
6922+
return true;
6923+
}
6924+
}
6925+
69116926
bool isOpenCL() const {
69126927
return getOp() >= AO__opencl_atomic_compare_exchange_strong &&
69136928
getOp() <= AO__opencl_atomic_store;

clang/lib/AST/StmtPrinter.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,11 +2024,7 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
20242024

20252025
// AtomicExpr stores its subexpressions in a permuted order.
20262026
PrintExpr(Node->getPtr());
2027-
if (Node->getOp() != AtomicExpr::AO__c11_atomic_load &&
2028-
Node->getOp() != AtomicExpr::AO__atomic_load_n &&
2029-
Node->getOp() != AtomicExpr::AO__scoped_atomic_load_n &&
2030-
Node->getOp() != AtomicExpr::AO__opencl_atomic_load &&
2031-
Node->getOp() != AtomicExpr::AO__hip_atomic_load) {
2027+
if (Node->hasVal1Operand()) {
20322028
OS << ", ";
20332029
PrintExpr(Node->getVal1());
20342030
}

clang/test/SemaCXX/ast-print.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,98 @@ float test15() {
176176
return __builtin_asinf(1.0F);
177177
}
178178

179+
// CHECK: void test_atomic_loads(int *ptr, int *ret, int memorder) {
180+
// CHECK: __atomic_load_n(ptr, memorder);
181+
// CHECK: __atomic_load(ptr, ret, memorder);
182+
// CHECK: }
183+
void test_atomic_loads(int *ptr, int *ret, int memorder) {
184+
__atomic_load_n(ptr, memorder);
185+
__atomic_load(ptr, ret, memorder);
186+
}
187+
188+
// CHECK: void test_atomic_stores(int *ptr, int val, int memorder) {
189+
// CHECK: __atomic_store_n(ptr, val, memorder);
190+
// CHECK: __atomic_store(ptr, &val, memorder);
191+
// CHECK: }
192+
void test_atomic_stores(int *ptr, int val, int memorder) {
193+
__atomic_store_n(ptr, val, memorder);
194+
__atomic_store(ptr, &val, memorder);
195+
}
196+
197+
// CHECK: void test_atomic_exchanges(int *ptr, int val, int *ret, int memorder) {
198+
// CHECK: __atomic_exchange_n(ptr, val, memorder);
199+
// CHECK: __atomic_exchange(ptr, &val, ret, memorder);
200+
// CHECK: }
201+
void test_atomic_exchanges(int *ptr, int val, int *ret, int memorder) {
202+
__atomic_exchange_n(ptr, val, memorder);
203+
__atomic_exchange(ptr, &val, ret, memorder);
204+
}
205+
206+
// CHECK: void test_atomic_cmpxchgs(int *ptr, int *expected, int desired, bool weak, int success_memorder, int failure_memorder) {
207+
// CHECK: __atomic_compare_exchange_n(ptr, expected, desired, weak, success_memorder, failure_memorder);
208+
// CHECK: __atomic_compare_exchange(ptr, expected, &desired, weak, success_memorder, failure_memorder);
209+
// CHECK: }
210+
void test_atomic_cmpxchgs(int *ptr, int *expected, int desired, bool weak, int success_memorder, int failure_memorder) {
211+
__atomic_compare_exchange_n(ptr, expected, desired, weak, success_memorder, failure_memorder);
212+
__atomic_compare_exchange(ptr, expected, &desired, weak, success_memorder, failure_memorder);
213+
}
214+
215+
// CHECK: void test_atomic_fetch_ops(int *ptr, int val, int memorder) {
216+
// CHECK: __atomic_add_fetch(ptr, val, memorder);
217+
// CHECK: __atomic_sub_fetch(ptr, val, memorder);
218+
// CHECK: __atomic_and_fetch(ptr, val, memorder);
219+
// CHECK: __atomic_xor_fetch(ptr, val, memorder);
220+
// CHECK: __atomic_or_fetch(ptr, val, memorder);
221+
// CHECK: __atomic_nand_fetch(ptr, val, memorder);
222+
// CHECK: __atomic_fetch_add(ptr, val, memorder);
223+
// CHECK: __atomic_fetch_sub(ptr, val, memorder);
224+
// CHECK: __atomic_fetch_and(ptr, val, memorder);
225+
// CHECK: __atomic_fetch_xor(ptr, val, memorder);
226+
// CHECK: __atomic_fetch_or(ptr, val, memorder);
227+
// CHECK: __atomic_fetch_nand(ptr, val, memorder);
228+
// CHECK: }
229+
void test_atomic_fetch_ops(int *ptr, int val, int memorder) {
230+
__atomic_add_fetch(ptr, val, memorder);
231+
__atomic_sub_fetch(ptr, val, memorder);
232+
__atomic_and_fetch(ptr, val, memorder);
233+
__atomic_xor_fetch(ptr, val, memorder);
234+
__atomic_or_fetch(ptr, val, memorder);
235+
__atomic_nand_fetch(ptr, val, memorder);
236+
__atomic_fetch_add(ptr, val, memorder);
237+
__atomic_fetch_sub(ptr, val, memorder);
238+
__atomic_fetch_and(ptr, val, memorder);
239+
__atomic_fetch_xor(ptr, val, memorder);
240+
__atomic_fetch_or(ptr, val, memorder);
241+
__atomic_fetch_nand(ptr, val, memorder);
242+
}
243+
244+
// CHECK: void test_atomic_setclear(void *ptr, int memorder) {
245+
// CHECK: __atomic_test_and_set(ptr, memorder);
246+
// CHECK: __atomic_clear(ptr, memorder);
247+
// CHECK: }
248+
void test_atomic_setclear(void *ptr, int memorder) {
249+
__atomic_test_and_set(ptr, memorder);
250+
__atomic_clear(ptr, memorder);
251+
}
252+
253+
// CHECK: void test_atomic_fences(int memorder) {
254+
// CHECK: __atomic_thread_fence(memorder);
255+
// CHECK: __atomic_signal_fence(memorder);
256+
// CHECK: }
257+
void test_atomic_fences(int memorder) {
258+
__atomic_thread_fence(memorder);
259+
__atomic_signal_fence(memorder);
260+
}
261+
262+
// CHECK: void test_atomic_lockfree(unsigned long size, void *ptr) {
263+
// CHECK: __atomic_always_lock_free(size, ptr);
264+
// CHECK: __atomic_is_lock_free(size, ptr);
265+
// CHECK: }
266+
void test_atomic_lockfree(unsigned long size, void *ptr) {
267+
__atomic_always_lock_free(size, ptr);
268+
__atomic_is_lock_free(size, ptr);
269+
}
270+
179271
namespace PR18776 {
180272
struct A {
181273
operator void *();

0 commit comments

Comments
 (0)