[clang] ba49062 - [Clang][AST] Fix printing for `atomic_test_and_set` and `atomic_clear` (#159712)

via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 19 06:17:49 PDT 2025


Author: Devajith
Date: 2025-09-19T15:17:45+02:00
New Revision: ba49062914f01f68cf3c4e067139a24b29a0e45b

URL: https://github.com/llvm/llvm-project/commit/ba49062914f01f68cf3c4e067139a24b29a0e45b
DIFF: https://github.com/llvm/llvm-project/commit/ba49062914f01f68cf3c4e067139a24b29a0e45b.diff

LOG: [Clang][AST] Fix printing for `atomic_test_and_set` and `atomic_clear` (#159712)

https://github.com/llvm/llvm-project/pull/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.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/Expr.h
    clang/lib/AST/StmtPrinter.cpp
    clang/test/SemaCXX/ast-print.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c898784b3f93e..ed668ca6f207c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -114,6 +114,15 @@ AST Dumping Potentially Breaking Changes
 ----------------------------------------
 - How nested name specifiers are dumped and printed changes, keeping track of clang AST changes.
 
+- Pretty-printing of atomic builtins ``__atomic_test_and_set`` and ``__atomic_clear`` in ``-ast-print`` output.
+  These previously displayed an extra ``<null expr>`` argument, e.g.:
+
+    ``__atomic_test_and_set(p, <null expr>, 0)``
+
+  Now they are printed as:
+
+    ``__atomic_test_and_set(p, 0)``
+
 Clang Frontend Potentially Breaking Changes
 -------------------------------------------
 - Members of anonymous unions/structs are now injected as ``IndirectFieldDecl``

diff  --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 9eb1a86931b11..e1a4005d1a890 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -6908,6 +6908,21 @@ class AtomicExpr : public Expr {
            getOp() == AO__scoped_atomic_compare_exchange_n;
   }
 
+  bool hasVal1Operand() const {
+    switch (getOp()) {
+    case AO__atomic_load_n:
+    case AO__scoped_atomic_load_n:
+    case AO__c11_atomic_load:
+    case AO__opencl_atomic_load:
+    case AO__hip_atomic_load:
+    case AO__atomic_test_and_set:
+    case AO__atomic_clear:
+      return false;
+    default:
+      return true;
+    }
+  }
+
   bool isOpenCL() const {
     return getOp() >= AO__opencl_atomic_compare_exchange_strong &&
            getOp() <= AO__opencl_atomic_store;

diff  --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 0030300521128..2c9c3581a2962 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2024,11 +2024,7 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
 
   // AtomicExpr stores its subexpressions in a permuted order.
   PrintExpr(Node->getPtr());
-  if (Node->getOp() != AtomicExpr::AO__c11_atomic_load &&
-      Node->getOp() != AtomicExpr::AO__atomic_load_n &&
-      Node->getOp() != AtomicExpr::AO__scoped_atomic_load_n &&
-      Node->getOp() != AtomicExpr::AO__opencl_atomic_load &&
-      Node->getOp() != AtomicExpr::AO__hip_atomic_load) {
+  if (Node->hasVal1Operand()) {
     OS << ", ";
     PrintExpr(Node->getVal1());
   }

diff  --git a/clang/test/SemaCXX/ast-print.cpp b/clang/test/SemaCXX/ast-print.cpp
index 2cb1ec440b6bb..616fcac64c6f4 100644
--- a/clang/test/SemaCXX/ast-print.cpp
+++ b/clang/test/SemaCXX/ast-print.cpp
@@ -176,6 +176,98 @@ float test15() {
   return __builtin_asinf(1.0F);
 }
 
+// CHECK: void test_atomic_loads(int *ptr, int *ret, int memorder) {
+// CHECK:   __atomic_load_n(ptr, memorder);
+// CHECK:   __atomic_load(ptr, ret, memorder);
+// CHECK: }
+void test_atomic_loads(int *ptr, int *ret, int memorder) {
+  __atomic_load_n(ptr, memorder);
+  __atomic_load(ptr, ret, memorder);
+}
+
+// CHECK: void test_atomic_stores(int *ptr, int val, int memorder) {
+// CHECK:   __atomic_store_n(ptr, val, memorder);
+// CHECK:   __atomic_store(ptr, &val, memorder);
+// CHECK: }
+void test_atomic_stores(int *ptr, int val, int memorder) {
+  __atomic_store_n(ptr, val, memorder);
+  __atomic_store(ptr, &val, memorder);
+}
+
+// CHECK: void test_atomic_exchanges(int *ptr, int val, int *ret, int memorder) {
+// CHECK:   __atomic_exchange_n(ptr, val, memorder);
+// CHECK:   __atomic_exchange(ptr, &val, ret, memorder);
+// CHECK: }
+void test_atomic_exchanges(int *ptr, int val, int *ret, int memorder) {
+  __atomic_exchange_n(ptr, val, memorder);
+  __atomic_exchange(ptr, &val, ret, memorder);
+}
+
+// CHECK: void test_atomic_cmpxchgs(int *ptr, int *expected, int desired, bool weak, int success_memorder, int failure_memorder) {
+// CHECK:   __atomic_compare_exchange_n(ptr, expected, desired, weak, success_memorder, failure_memorder);
+// CHECK:   __atomic_compare_exchange(ptr, expected, &desired, weak, success_memorder, failure_memorder);
+// CHECK: }
+void test_atomic_cmpxchgs(int *ptr, int *expected, int desired, bool weak, int success_memorder, int failure_memorder) {
+  __atomic_compare_exchange_n(ptr, expected, desired, weak, success_memorder, failure_memorder);
+  __atomic_compare_exchange(ptr, expected, &desired, weak, success_memorder, failure_memorder);
+}
+
+// CHECK: void test_atomic_fetch_ops(int *ptr, int val, int memorder) {
+// CHECK:   __atomic_add_fetch(ptr, val, memorder);
+// CHECK:   __atomic_sub_fetch(ptr, val, memorder);
+// CHECK:   __atomic_and_fetch(ptr, val, memorder);
+// CHECK:   __atomic_xor_fetch(ptr, val, memorder);
+// CHECK:   __atomic_or_fetch(ptr, val, memorder);
+// CHECK:   __atomic_nand_fetch(ptr, val, memorder);
+// CHECK:   __atomic_fetch_add(ptr, val, memorder);
+// CHECK:   __atomic_fetch_sub(ptr, val, memorder);
+// CHECK:   __atomic_fetch_and(ptr, val, memorder);
+// CHECK:   __atomic_fetch_xor(ptr, val, memorder);
+// CHECK:   __atomic_fetch_or(ptr, val, memorder);
+// CHECK:   __atomic_fetch_nand(ptr, val, memorder);
+// CHECK: }
+void test_atomic_fetch_ops(int *ptr, int val, int memorder) {
+  __atomic_add_fetch(ptr, val, memorder);
+  __atomic_sub_fetch(ptr, val, memorder);
+  __atomic_and_fetch(ptr, val, memorder);
+  __atomic_xor_fetch(ptr, val, memorder);
+  __atomic_or_fetch(ptr, val, memorder);
+  __atomic_nand_fetch(ptr, val, memorder);
+  __atomic_fetch_add(ptr, val, memorder);
+  __atomic_fetch_sub(ptr, val, memorder);
+  __atomic_fetch_and(ptr, val, memorder);
+  __atomic_fetch_xor(ptr, val, memorder);
+  __atomic_fetch_or(ptr, val, memorder);
+  __atomic_fetch_nand(ptr, val, memorder);
+}
+
+// CHECK: void test_atomic_setclear(void *ptr, int memorder) {
+// CHECK:   __atomic_test_and_set(ptr, memorder);
+// CHECK:   __atomic_clear(ptr, memorder);
+// CHECK: }
+void test_atomic_setclear(void *ptr, int memorder) {
+  __atomic_test_and_set(ptr, memorder);
+  __atomic_clear(ptr, memorder);
+}
+
+// CHECK: void test_atomic_fences(int memorder) {
+// CHECK:   __atomic_thread_fence(memorder);
+// CHECK:   __atomic_signal_fence(memorder);
+// CHECK: }
+void test_atomic_fences(int memorder) {
+  __atomic_thread_fence(memorder);
+  __atomic_signal_fence(memorder);
+}
+
+// CHECK: void test_atomic_lockfree(unsigned long size, void *ptr) {
+// CHECK:   __atomic_always_lock_free(size, ptr);
+// CHECK:   __atomic_is_lock_free(size, ptr);
+// CHECK: }
+void test_atomic_lockfree(unsigned long size, void *ptr) {
+  __atomic_always_lock_free(size, ptr);
+  __atomic_is_lock_free(size, ptr);
+}
+
 namespace PR18776 {
 struct A {
   operator void *();


        


More information about the cfe-commits mailing list