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 ```` argument, e.g.: + + ``__atomic_test_and_set(p, , 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 *();