From fafbf06732746f3ceca21d452d77b144ba8652ae Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 11 Apr 2012 17:55:32 +0000 Subject: [PATCH] Provide, and document, a set of __c11_atomic_* intrinsics to implement C11's header. In passing, fix LanguageExtensions to note that C11 and C++11 are no longer "upcoming standards" but are now actually standardized. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154513 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LanguageExtensions.html | 100 ++++++++++++++++++++---------- include/clang/Basic/Builtins.def | 17 +++++ lib/AST/ExprConstant.cpp | 3 +- lib/AST/StmtPrinter.cpp | 22 +++---- lib/CodeGen/CGBuiltin.cpp | 7 ++- lib/Sema/SemaChecking.cpp | 21 +++++-- test/CodeGen/atomic-ops.c | 36 +++++------ test/CodeGen/atomic_init.c | 4 +- test/Preprocessor/feature_tests.c | 1 + test/Sema/atomic-ops.c | 52 ++++++++-------- 10 files changed, 165 insertions(+), 98 deletions(-) diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index 9da30b9c0d..68f0afc1ff 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -34,15 +34,14 @@
  • Availability attribute
  • Checks for Standard Language Features
  • + +
  • Checks for Type Traits
  • Blocks
  • Objective-C Features @@ -91,7 +91,7 @@
  • Automatic reference counting
  • Enumerations with a fixed underlying type
  • Interoperability with C++11 lambdas
  • -
  • Object Literals and Subscripting
  • +
  • Object Literals and Subscripting
  • Function Overloading in C
  • @@ -707,33 +707,32 @@ linked, as if the weak_import attribute were added to the decla

    Checks for Standard Language Features

    -

    The __has_feature macro can be used to query if certain standard language features are -enabled. Those features are listed here.

    +

    The __has_feature macro can be used to query if certain standard +language features are enabled. The __has_extension macro can be used +to query if language features are available as an extension when compiling for +a standard which does not provide them. The features which can be tested are +listed here.

    + +

    C++98

    -

    C++ exceptions

    +

    The features listed below are part of the C++98 standard. These features are +enabled by default when compiling C++ code.

    + +

    C++ exceptions

    Use __has_feature(cxx_exceptions) to determine if C++ exceptions have been enabled. For -example, compiling code with -fexceptions enables C++ exceptions.

    +example, compiling code with -fno-exceptions disables C++ exceptions.

    -

    C++ RTTI

    +

    C++ RTTI

    Use __has_feature(cxx_rtti) to determine if C++ RTTI has been enabled. For example, compiling code with -fno-rtti disables the use of RTTI.

    - -

    Checks for Upcoming Standard Language Features

    - - -

    The __has_feature or __has_extension macros can be used -to query if certain upcoming standard language features are enabled. Those -features are listed here. Features that are not yet implemented will be -noted.

    - -

    C++11

    +

    C++11

    -

    The features listed below are slated for inclusion in the upcoming -C++11 standard. As a result, all these features are enabled -with the -std=c++11 option when compiling C++ code.

    +

    The features listed below are part of the C++11 standard. As a result, all +these features are enabled with the -std=c++11 or -std=gnu++11 +option when compiling C++ code.

    C++11 SFINAE includes access control

    @@ -922,9 +921,10 @@ for variadic templates is enabled.

    C11

    -

    The features listed below are slated for inclusion in the upcoming -C11 standard. As a result, all these features are enabled -with the -std=c11 option when compiling C code.

    +

    The features listed below are part of the C11 standard. As a result, all +these features are enabled with the -std=c11 or -std=gnu11 +option when compiling C code. Additionally, because these features are all +backward-compatible, they are available as extensions in all language modes.

    C11 alignment specifiers

    @@ -932,6 +932,14 @@ with the -std=c11 option when compiling C code.

    to determine if support for alignment specifiers using _Alignas is enabled.

    +

    C11 atomic operations

    + +

    Use __has_feature(c_atomic) or __has_extension(c_atomic) +to determine if support for atomic types using _Atomic is enabled. +Clang also provides a set of builtins which can be +used to implement the <stdatomic.h> operations on _Atomic +types.

    +

    C11 generic selections

    Use __has_feature(c_generic_selections) or @@ -1455,6 +1463,32 @@ relying on the platform specific implementation details of __sync_lock_test_and_set(). The __sync_swap() builtin is a full barrier.

    + +

    __c11_atomic builtins

    + + +

    Clang provides a set of builtins which are intended to be used to implement +C11's <stdatomic.h> header. These builtins provide the semantics +of the _explicit form of the corresponding C11 operation, and are named +with a __c11_ prefix. The supported operations are:

    + + +

    Target-Specific Extensions

    diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index f811316d57..82f0463d8c 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -594,6 +594,23 @@ BUILTIN(__sync_swap_4, "iiD*i.", "tn") BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "tn") BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "tn") +// C11 _Atomic operations for . +BUILTIN(__c11_atomic_load, "v.", "t") +BUILTIN(__c11_atomic_store, "v.", "t") +BUILTIN(__c11_atomic_exchange, "v.", "t") +BUILTIN(__c11_atomic_compare_exchange_strong, "v.", "t") +BUILTIN(__c11_atomic_compare_exchange_weak, "v.", "t") +BUILTIN(__c11_atomic_fetch_add, "v.", "t") +BUILTIN(__c11_atomic_fetch_sub, "v.", "t") +BUILTIN(__c11_atomic_fetch_and, "v.", "t") +BUILTIN(__c11_atomic_fetch_or, "v.", "t") +BUILTIN(__c11_atomic_fetch_xor, "v.", "t") +BUILTIN(__c11_atomic_thread_fence, "vi", "n") +BUILTIN(__c11_atomic_signal_fence, "vi", "n") +BUILTIN(__c11_atomic_init, "v.", "t") +BUILTIN(__c11_atomic_is_lock_free, "iz", "n") + +// FIXME: Convert these to implementing GNU atomic builtins. BUILTIN(__atomic_load, "v.", "t") BUILTIN(__atomic_store, "v.", "t") BUILTIN(__atomic_exchange, "v.", "t") diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 435d94c1d4..ce41308344 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -4365,7 +4365,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Error(E); - case Builtin::BI__atomic_is_lock_free: { + case Builtin::BI__atomic_is_lock_free: + case Builtin::BI__c11_atomic_is_lock_free: { APSInt SizeVal; if (!EvaluateInteger(E->getArg(0), SizeVal, Info)) return false; diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index ef5eefb306..651b88b5d3 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1109,37 +1109,37 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { const char *Name = 0; switch (Node->getOp()) { case AtomicExpr::Init: - Name = "__atomic_init("; + Name = "__c11_atomic_init("; break; case AtomicExpr::Load: - Name = "__atomic_load("; + Name = "__c11_atomic_load("; break; case AtomicExpr::Store: - Name = "__atomic_store("; + Name = "__c11_atomic_store("; break; case AtomicExpr::CmpXchgStrong: - Name = "__atomic_compare_exchange_strong("; + Name = "__c11_atomic_compare_exchange_strong("; break; case AtomicExpr::CmpXchgWeak: - Name = "__atomic_compare_exchange_weak("; + Name = "__c11_atomic_compare_exchange_weak("; break; case AtomicExpr::Xchg: - Name = "__atomic_exchange("; + Name = "__c11_atomic_exchange("; break; case AtomicExpr::Add: - Name = "__atomic_fetch_add("; + Name = "__c11_atomic_fetch_add("; break; case AtomicExpr::Sub: - Name = "__atomic_fetch_sub("; + Name = "__c11_atomic_fetch_sub("; break; case AtomicExpr::And: - Name = "__atomic_fetch_and("; + Name = "__c11_atomic_fetch_and("; break; case AtomicExpr::Or: - Name = "__atomic_fetch_or("; + Name = "__c11_atomic_fetch_or("; break; case AtomicExpr::Xor: - Name = "__atomic_fetch_xor("; + Name = "__c11_atomic_fetch_xor("; break; } OS << Name; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index eb849f6e99..5eab5db94a 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -967,9 +967,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__atomic_thread_fence: - case Builtin::BI__atomic_signal_fence: { + case Builtin::BI__atomic_signal_fence: + case Builtin::BI__c11_atomic_thread_fence: + case Builtin::BI__c11_atomic_signal_fence: { llvm::SynchronizationScope Scope; - if (BuiltinID == Builtin::BI__atomic_signal_fence) + if (BuiltinID == Builtin::BI__atomic_signal_fence || + BuiltinID == Builtin::BI__c11_atomic_signal_fence) Scope = llvm::SingleThread; else Scope = llvm::CrossThread; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 74832fd32e..c4ed0b0e52 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -251,28 +251,39 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_swap_16: return SemaBuiltinAtomicOverloaded(move(TheCallResult)); case Builtin::BI__atomic_load: + case Builtin::BI__c11_atomic_load: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load); case Builtin::BI__atomic_store: + case Builtin::BI__c11_atomic_store: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store); case Builtin::BI__atomic_init: + case Builtin::BI__c11_atomic_init: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Init); case Builtin::BI__atomic_exchange: + case Builtin::BI__c11_atomic_exchange: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg); case Builtin::BI__atomic_compare_exchange_strong: + case Builtin::BI__c11_atomic_compare_exchange_strong: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::CmpXchgStrong); case Builtin::BI__atomic_compare_exchange_weak: + case Builtin::BI__c11_atomic_compare_exchange_weak: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::CmpXchgWeak); case Builtin::BI__atomic_fetch_add: + case Builtin::BI__c11_atomic_fetch_add: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add); case Builtin::BI__atomic_fetch_sub: + case Builtin::BI__c11_atomic_fetch_sub: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub); case Builtin::BI__atomic_fetch_and: + case Builtin::BI__c11_atomic_fetch_and: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And); case Builtin::BI__atomic_fetch_or: + case Builtin::BI__c11_atomic_fetch_or: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or); case Builtin::BI__atomic_fetch_xor: + case Builtin::BI__c11_atomic_fetch_xor: return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor); case Builtin::BI__builtin_annotation: if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1))) @@ -510,11 +521,11 @@ Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); // All these operations take one of the following four forms: - // T __atomic_load(_Atomic(T)*, int) (loads) - // T* __atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub) - // int __atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int) - // (cmpxchg) - // T __atomic_exchange(_Atomic(T)*, T, int) (everything else) + // T __c11_atomic_load(_Atomic(T)*, int) (loads) + // T* __c11_atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub) + // int __c11_atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int) + // (cmpxchg) + // T __c11_atomic_exchange(_Atomic(T)*, T, int) (everything else) // where T is an appropriate type, and the int paremeterss are for orderings. unsigned NumVals = 1; unsigned NumOrders = 1; diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c index 2285cca723..c94f14023e 100644 --- a/test/CodeGen/atomic-ops.c +++ b/test/CodeGen/atomic-ops.c @@ -7,9 +7,9 @@ #ifndef ALREADY_INCLUDED #define ALREADY_INCLUDED -// Basic IRGen tests for __atomic_* +// Basic IRGen tests for __c11_atomic_* -// FIXME: Need to implement __atomic_is_lock_free +// FIXME: Need to implement __c11_atomic_is_lock_free typedef enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, @@ -19,74 +19,74 @@ typedef enum memory_order { int fi1(_Atomic(int) *i) { // CHECK: @fi1 // CHECK: load atomic i32* {{.*}} seq_cst - return __atomic_load(i, memory_order_seq_cst); + return __c11_atomic_load(i, memory_order_seq_cst); } void fi2(_Atomic(int) *i) { // CHECK: @fi2 // CHECK: store atomic i32 {{.*}} seq_cst - __atomic_store(i, 1, memory_order_seq_cst); + __c11_atomic_store(i, 1, memory_order_seq_cst); } void fi3(_Atomic(int) *i) { // CHECK: @fi3 // CHECK: atomicrmw and - __atomic_fetch_and(i, 1, memory_order_seq_cst); + __c11_atomic_fetch_and(i, 1, memory_order_seq_cst); } void fi4(_Atomic(int) *i) { // CHECK: @fi4 // CHECK: cmpxchg i32* int cmp = 0; - __atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire); + __c11_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire); } float ff1(_Atomic(float) *d) { // CHECK: @ff1 // CHECK: load atomic i32* {{.*}} monotonic - return __atomic_load(d, memory_order_relaxed); + return __c11_atomic_load(d, memory_order_relaxed); } void ff2(_Atomic(float) *d) { // CHECK: @ff2 // CHECK: store atomic i32 {{.*}} release - __atomic_store(d, 1, memory_order_release); + __c11_atomic_store(d, 1, memory_order_release); } float ff3(_Atomic(float) *d) { - return __atomic_exchange(d, 2, memory_order_seq_cst); + return __c11_atomic_exchange(d, 2, memory_order_seq_cst); } int* fp1(_Atomic(int*) *p) { // CHECK: @fp1 // CHECK: load atomic i32* {{.*}} seq_cst - return __atomic_load(p, memory_order_seq_cst); + return __c11_atomic_load(p, memory_order_seq_cst); } int* fp2(_Atomic(int*) *p) { // CHECK: @fp2 // CHECK: store i32 4 // CHECK: atomicrmw add {{.*}} monotonic - return __atomic_fetch_add(p, 1, memory_order_relaxed); + return __c11_atomic_fetch_add(p, 1, memory_order_relaxed); } _Complex float fc(_Atomic(_Complex float) *c) { // CHECK: @fc // CHECK: atomicrmw xchg i64* - return __atomic_exchange(c, 2, memory_order_seq_cst); + return __c11_atomic_exchange(c, 2, memory_order_seq_cst); } typedef struct X { int x; } X; X fs(_Atomic(X) *c) { // CHECK: @fs // CHECK: atomicrmw xchg i32* - return __atomic_exchange(c, (X){2}, memory_order_seq_cst); + return __c11_atomic_exchange(c, (X){2}, memory_order_seq_cst); } int lock_free() { // CHECK: @lock_free // CHECK: ret i32 1 - return __atomic_is_lock_free(sizeof(_Atomic(int))); + return __c11_atomic_is_lock_free(sizeof(_Atomic(int))); } // Tests for atomic operations on big values. These should call the functions @@ -102,18 +102,18 @@ _Atomic(struct foo) bigAtomic; void structAtomicStore() { // CHECK: @structAtomicStore struct foo f = {0}; - __atomic_store(&bigAtomic, f, 5); + __c11_atomic_store(&bigAtomic, f, 5); // CHECK: call void @__atomic_store(i32 512, i8* bitcast (%struct.foo* @bigAtomic to i8*), } void structAtomicLoad() { // CHECK: @structAtomicLoad - struct foo f = __atomic_load(&bigAtomic, 5); + struct foo f = __c11_atomic_load(&bigAtomic, 5); // CHECK: call void @__atomic_load(i32 512, i8* bitcast (%struct.foo* @bigAtomic to i8*), } struct foo structAtomicExchange() { // CHECK: @structAtomicExchange struct foo f = {0}; - return __atomic_exchange(&bigAtomic, f, 5); + return __c11_atomic_exchange(&bigAtomic, f, 5); // CHECK: call void @__atomic_exchange(i32 512, i8* bitcast (%struct.foo* @bigAtomic to i8*), } int structAtomicCmpExchange() { @@ -121,7 +121,7 @@ int structAtomicCmpExchange() { struct foo f = {0}; struct foo g = {0}; g.big[12] = 12; - return __atomic_compare_exchange_strong(&bigAtomic, &f, g, 5, 5); + return __c11_atomic_compare_exchange_strong(&bigAtomic, &f, g, 5, 5); // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast (%struct.foo* @bigAtomic to i8*), } diff --git a/test/CodeGen/atomic_init.c b/test/CodeGen/atomic_init.c index 243eb602cb..6f773bef48 100644 --- a/test/CodeGen/atomic_init.c +++ b/test/CodeGen/atomic_init.c @@ -9,6 +9,6 @@ void foo() { _Atomic(int) j = 12; // CHECK: store // CHECK-NOT: atomic - __atomic_init(&j, 42); // CHECK: store - // CHECK-NOT: atomic + __c11_atomic_init(&j, 42); // CHECK: store + // CHECK-NOT: atomic } diff --git a/test/Preprocessor/feature_tests.c b/test/Preprocessor/feature_tests.c index be9c62d780..b78a2517b1 100644 --- a/test/Preprocessor/feature_tests.c +++ b/test/Preprocessor/feature_tests.c @@ -12,6 +12,7 @@ #if !__has_builtin(__builtin_huge_val) || \ !__has_builtin(__builtin_shufflevector) || \ !__has_builtin(__builtin_trap) || \ + !__has_builtin(__c11_atomic_init) || \ !__has_feature(attribute_analyzer_noreturn) || \ !__has_feature(attribute_overloadable) #error Clang should have these diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c index 51b46bd5d0..0560a747ab 100644 --- a/test/Sema/atomic-ops.c +++ b/test/Sema/atomic-ops.c @@ -1,8 +1,8 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only -// Basic parsing/Sema tests for __atomic_* +// Basic parsing/Sema tests for __c11_atomic_* -// FIXME: Need to implement __atomic_is_lock_free +// FIXME: Need to implement __c11_atomic_is_lock_free typedef enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, @@ -10,28 +10,28 @@ typedef enum memory_order { } memory_order; void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d) { - __atomic_load(0); // expected-error {{too few arguments to function}} - __atomic_load(0,0,0); // expected-error {{too many arguments to function}} - __atomic_store(0,0,0); // expected-error {{first argument to atomic operation}} - __atomic_store((int*)0,0,0); // expected-error {{first argument to atomic operation}} - - __atomic_load(i, memory_order_seq_cst); - __atomic_load(p, memory_order_seq_cst); - __atomic_load(d, memory_order_seq_cst); - - __atomic_store(i, 1, memory_order_seq_cst); - __atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}} - (int)__atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}} - - __atomic_fetch_add(i, 1, memory_order_seq_cst); - __atomic_fetch_add(p, 1, memory_order_seq_cst); - __atomic_fetch_add(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer or pointer}} - - __atomic_fetch_and(i, 1, memory_order_seq_cst); - __atomic_fetch_and(p, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} - __atomic_fetch_and(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} - - __atomic_compare_exchange_strong(i, 0, 1, memory_order_seq_cst, memory_order_seq_cst); - __atomic_compare_exchange_strong(p, 0, (int*)1, memory_order_seq_cst, memory_order_seq_cst); - __atomic_compare_exchange_strong(d, (int*)0, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}} + __c11_atomic_load(0); // expected-error {{too few arguments to function}} + __c11_atomic_load(0,0,0); // expected-error {{too many arguments to function}} + __c11_atomic_store(0,0,0); // expected-error {{first argument to atomic operation}} + __c11_atomic_store((int*)0,0,0); // expected-error {{first argument to atomic operation}} + + __c11_atomic_load(i, memory_order_seq_cst); + __c11_atomic_load(p, memory_order_seq_cst); + __c11_atomic_load(d, memory_order_seq_cst); + + __c11_atomic_store(i, 1, memory_order_seq_cst); + __c11_atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}} + (int)__c11_atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}} + + __c11_atomic_fetch_add(i, 1, memory_order_seq_cst); + __c11_atomic_fetch_add(p, 1, memory_order_seq_cst); + __c11_atomic_fetch_add(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer or pointer}} + + __c11_atomic_fetch_and(i, 1, memory_order_seq_cst); + __c11_atomic_fetch_and(p, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} + __c11_atomic_fetch_and(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} + + __c11_atomic_compare_exchange_strong(i, 0, 1, memory_order_seq_cst, memory_order_seq_cst); + __c11_atomic_compare_exchange_strong(p, 0, (int*)1, memory_order_seq_cst, memory_order_seq_cst); + __c11_atomic_compare_exchange_strong(d, (int*)0, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}} } -- 2.40.0