Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7066,6 +7066,9 @@ def warn_atomic_op_misaligned : Warning< "misaligned or large atomic operation may incur significant performance penalty">, InGroup>; +def warn_atomic_implicit_seq_cst : Warning< + "implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary">, + InGroup>, DefaultIgnore; def err_overflow_builtin_must_be_int : Error< "operand argument to overflow builtin must be an integer (%0 invalid)">; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1124,6 +1124,10 @@ case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: return SemaBuiltinAtomicOverloaded(TheCallResult); + case Builtin::BI__sync_synchronize: + Diag(TheCall->getBeginLoc(), diag::warn_atomic_implicit_seq_cst) + << TheCall->getCallee()->getSourceRange(); + break; case Builtin::BI__builtin_nontemporal_load: case Builtin::BI__builtin_nontemporal_store: return SemaBuiltinNontemporalOverloaded(TheCallResult); @@ -4612,25 +4616,24 @@ return false; } -/// SemaBuiltinAtomicOverloaded - We have a call to a function like -/// __sync_fetch_and_add, which is an overloaded function based on the pointer -/// type of its first argument. The main ActOnCallExpr routines have already -/// promoted the types of arguments because all of these calls are prototyped as -/// void(...). +/// We have a call to a function like __sync_fetch_and_add, which is an +/// overloaded function based on the pointer type of its first argument. +/// The main ActOnCallExpr routines have already promoted the types of +/// arguments because all of these calls are prototyped as void(...). /// /// This function goes through and does final semantic checking for these -/// builtins, +/// builtins, as well as generating any warnings. ExprResult Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { - CallExpr *TheCall = (CallExpr *)TheCallResult.get(); - DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); + CallExpr *TheCall = static_cast(TheCallResult.get()); + Expr *Callee = TheCall->getCallee(); + DeclRefExpr *DRE = cast(Callee->IgnoreParenCasts()); FunctionDecl *FDecl = cast(DRE->getDecl()); // Ensure that we have at least one argument to do type inference from. if (TheCall->getNumArgs() < 1) { Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) - << 0 << 1 << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + << 0 << 1 << TheCall->getNumArgs() << Callee->getSourceRange(); return ExprError(); } @@ -4907,13 +4910,16 @@ if (TheCall->getNumArgs() < 1+NumFixed) { Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) << 0 << 1 + NumFixed << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + << Callee->getSourceRange(); return ExprError(); } + Diag(TheCall->getEndLoc(), diag::warn_atomic_implicit_seq_cst) + << Callee->getSourceRange(); + if (WarnAboutSemanticsChange) { Diag(TheCall->getEndLoc(), diag::warn_sync_fetch_and_nand_semantics_change) - << TheCall->getCallee()->getSourceRange(); + << Callee->getSourceRange(); } // Get the decl for the concrete builtin from this, we can tell what the @@ -10258,6 +10264,10 @@ } AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); + + // Diagnose implicitly sequentially-consistent atomic assignment. + if (E->getLHS()->getType()->isAtomicType()) + S.Diag(E->getRHS()->getBeginLoc(), diag::warn_atomic_implicit_seq_cst); } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. @@ -10393,6 +10403,9 @@ AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); + if (E->getLHS()->getType()->isAtomicType()) + S.Diag(E->getOperatorLoc(), diag::warn_atomic_implicit_seq_cst); + // Now check the outermost expression const auto *ResultBT = E->getLHS()->getType()->getAs(); const auto *RBT = cast(E) @@ -10654,6 +10667,9 @@ if (CC.isInvalid()) return; + if (Source->isAtomicType()) + S.Diag(E->getExprLoc(), diag::warn_atomic_implicit_seq_cst); + // Diagnose implicit casts to bool. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) { if (isa(E)) @@ -10949,11 +10965,13 @@ E->getType(), CC, &Suspicious); } -/// CheckBoolLikeConversion - Check conversion of given expression to boolean. +/// Check conversion of given expression to boolean. /// Input argument E is a logical expression. static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { if (S.getLangOpts().Bool) return; + if (E->IgnoreParenImpCasts()->getType()->isAtomicType()) + return; CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); } @@ -10998,8 +11016,10 @@ } // Skip past explicit casts. - if (isa(E)) { - E = cast(E)->getSubExpr()->IgnoreParenImpCasts(); + if (auto *CE = dyn_cast(E)) { + E = CE->getSubExpr()->IgnoreParenImpCasts(); + if (!CE->getType()->isVoidType() && E->getType()->isAtomicType()) + S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst); return AnalyzeImplicitConversions(S, E, CC); } @@ -11052,9 +11072,15 @@ ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc()); } - if (const UnaryOperator *U = dyn_cast(E)) - if (U->getOpcode() == UO_LNot) + if (const UnaryOperator *U = dyn_cast(E)) { + if (U->getOpcode() == UO_LNot) { ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); + } else if (U->getOpcode() != UO_AddrOf) { + if (U->getSubExpr()->getType()->isAtomicType()) + S.Diag(U->getSubExpr()->getBeginLoc(), + diag::warn_atomic_implicit_seq_cst); + } + } } /// Diagnose integer type and any valid implicit conversion to it. Index: test/Sema/atomic-implicit-seq_cst.c =================================================================== --- /dev/null +++ test/Sema/atomic-implicit-seq_cst.c @@ -0,0 +1,325 @@ +// RUN: %clang_cc1 %s -verify -ffreestanding -fsyntax-only -triple=i686-linux-gnu -std=c11 -Watomic-implicit-seq-cst + +// _Atomic operations are implicitly sequentially-consistent. Some codebases +// want to force explicit usage of memory order instead. + +_Atomic(int) atom; +void gimme_int(int); + +void bad_pre_inc(void) { + ++atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_pre_dec(void) { + --atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_post_inc(void) { + atom++; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_post_dec(void) { + atom--; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_call(void) { + gimme_int(atom); // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_unary_plus(void) { + return +atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_unary_minus(void) { + return -atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_unary_logical_not(void) { + return !atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_unary_bitwise_not(void) { + return ~atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_explicit_cast(void) { + return (int)atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_implicit_cast(void) { + return atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_mul_1(int i) { + return atom * i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_mul_2(int i) { + return i * atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_div_1(int i) { + return atom / i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_div_2(int i) { + return i / atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_mod_1(int i) { + return atom % i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_mod_2(int i) { + return i % atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_add_1(int i) { + return atom + i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_add_2(int i) { + return i + atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_sub_1(int i) { + return atom - i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_sub_2(int i) { + return i - atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_shl_1(int i) { + return atom << i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_shl_2(int i) { + return i << atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_shr_1(int i) { + return atom >> i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_shr_2(int i) { + return i >> atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_lt_1(int i) { + return atom < i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_lt_2(int i) { + return i < atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_le_1(int i) { + return atom <= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_le_2(int i) { + return i <= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_gt_1(int i) { + return atom > i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_gt_2(int i) { + return i > atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_ge_1(int i) { + return atom >= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_ge_2(int i) { + return i >= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_eq_1(int i) { + return atom == i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_eq_2(int i) { + return i == atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_ne_1(int i) { + return atom != i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_ne_2(int i) { + return i != atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_bitand_1(int i) { + return atom & i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_bitand_2(int i) { + return i & atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_bitxor_1(int i) { + return atom ^ i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_bitxor_2(int i) { + return i ^ atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_bitor_1(int i) { + return atom | i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_bitor_2(int i) { + return i | atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_and_1(int i) { + return atom && i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_and_2(int i) { + return i && atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_or_1(int i) { + return atom || i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_or_2(int i) { + return i || atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} +int bad_ternary_1(int i, int j) { + return i ? atom : j; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_ternary_2(int i, int j) { + return atom ? i : j; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_ternary_3(int i, int j) { + return i ? j : atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_assign_1(int i) { + atom = i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_assign_2(int *i) { + *i = atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_assign_3() { + atom = atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_add_1(int i) { + atom += i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_add_2(int *i) { + *i += atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_sub_1(int i) { + atom -= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_sub_2(int *i) { + *i -= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_mul_1(int i) { + atom *= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_mul_2(int *i) { + *i *= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_div_1(int i) { + atom /= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_div_2(int *i) { + *i /= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_mod_1(int i) { + atom %= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_mod_2(int *i) { + *i %= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_shl_1(int i) { + atom <<= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_shl_2(int *i) { + *i <<= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_shr_1(int i) { + atom >>= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_shr_2(int *i) { + *i >>= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_bitand_1(int i) { + atom &= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_bitand_2(int *i) { + *i &= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_bitxor_1(int i) { + atom ^= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_bitxor_2(int *i) { + *i ^= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_bitor_1(int i) { + atom |= i; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void bad_compound_bitor_2(int *i) { + *i |= atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +int bad_comma(int i) { + return (void)i, atom; // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +} + +void good_c11_atomic_init(int i) { __c11_atomic_init(&atom, i); } +void good_c11_atomic_thread_fence(void) { __c11_atomic_thread_fence(__ATOMIC_RELAXED); } +void good_c11_atomic_signal_fence(void) { __c11_atomic_signal_fence(__ATOMIC_RELAXED); } +void good_c11_atomic_is_lock_free(void) { __c11_atomic_is_lock_free(sizeof(int)); } +void good_c11_atomic_store(int i) { __c11_atomic_store(&atom, i, __ATOMIC_RELAXED); } +int good_c11_atomic_load(void) { return __c11_atomic_load(&atom, __ATOMIC_RELAXED); } +int good_c11_atomic_exchange(int i) { return __c11_atomic_exchange(&atom, i, __ATOMIC_RELAXED); } +int good_c11_atomic_compare_exchange_strong(int *e, int i) { return __c11_atomic_compare_exchange_strong(&atom, e, i, __ATOMIC_RELAXED, __ATOMIC_RELAXED); } +int good_c11_atomic_compare_exchange_weak(int *e, int i) { return __c11_atomic_compare_exchange_weak(&atom, e, i, __ATOMIC_RELAXED, __ATOMIC_RELAXED); } +int good_c11_atomic_fetch_add(int i) { return __c11_atomic_fetch_add(&atom, i, __ATOMIC_RELAXED); } +int good_c11_atomic_fetch_sub(int i) { return __c11_atomic_fetch_sub(&atom, i, __ATOMIC_RELAXED); } +int good_c11_atomic_fetch_and(int i) { return __c11_atomic_fetch_and(&atom, i, __ATOMIC_RELAXED); } +int good_c11_atomic_fetch_or(int i) { return __c11_atomic_fetch_or(&atom, i, __ATOMIC_RELAXED); } +int good_c11_atomic_fetch_xor(int i) { return __c11_atomic_fetch_xor(&atom, i, __ATOMIC_RELAXED); } + +void good_cast_to_void(void) { (void)atom; } +_Atomic(int) * good_address_of(void) { return &atom; } +int good_sizeof(void) { return sizeof(atom); } +_Atomic(int) * good_pointer_arith(_Atomic(int) * p) { return p + 10; } +_Bool good_pointer_to_bool(_Atomic(int) * p) { return p; } +void good_no_init(void) { _Atomic(int) no_init; } +void good_init(void) { _Atomic(int) init = 42; } Index: test/Sema/sync-implicit-seq_cst.c =================================================================== --- /dev/null +++ test/Sema/sync-implicit-seq_cst.c @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 %s -verify -ffreestanding -fsyntax-only -triple=i686-linux-gnu -std=c11 -Watomic-implicit-seq-cst -Wno-sync-fetch-and-nand-semantics-changed + +// __sync_* operations are implicitly sequentially-consistent. Some codebases +// want to force explicit usage of memory order instead. + +void fetch_and_add(int *ptr, int val) { __sync_fetch_and_add(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void fetch_and_sub(int *ptr, int val) { __sync_fetch_and_sub(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void fetch_and_or(int *ptr, int val) { __sync_fetch_and_or(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void fetch_and_and(int *ptr, int val) { __sync_fetch_and_and(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void fetch_and_xor(int *ptr, int val) { __sync_fetch_and_xor(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void fetch_and_nand(int *ptr, int val) { __sync_fetch_and_nand(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} + +void add_and_fetch(int *ptr, int val) { __sync_add_and_fetch(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void sub_and_fetch(int *ptr, int val) { __sync_sub_and_fetch(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void or_and_fetch(int *ptr, int val) { __sync_or_and_fetch(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void and_and_fetch(int *ptr, int val) { __sync_and_and_fetch(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void xor_and_fetch(int *ptr, int val) { __sync_xor_and_fetch(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void nand_and_fetch(int *ptr, int val) { __sync_nand_and_fetch(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} + +void bool_compare_and_swap(int *ptr, int oldval, int newval) { __sync_bool_compare_and_swap(ptr, oldval, newval); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void val_compare_and_swap(int *ptr, int oldval, int newval) { __sync_val_compare_and_swap(ptr, oldval, newval); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} + +void synchronize(void) { __sync_synchronize(); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} + +void lock_test_and_set(int *ptr, int val) { __sync_lock_test_and_set(ptr, val); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}} +void lock_release(int *ptr) { __sync_lock_release(ptr); } // expected-warning {{implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary}}