forked from OSchip/llvm-project
Implement -Watomic-implicit-seq-cst
Summary: _Atomic and __sync_* operations are implicitly sequentially-consistent. Some codebases want to force explicit usage of memory order instead. This warning allows them to know where implicit sequentially-consistent memory order is used. The warning isn't on by default because _Atomic was purposefully designed to have seq_cst as the default: the idea was that it's the right thing to use most of the time. This warning allows developers who disagree to enforce explicit usage instead. A follow-up patch will take care of C++'s std::atomic. It'll be different enough from this patch that I think it should be separate: for C++ the atomic operations all have a memory order parameter (or two), but it's defaulted. I believe this warning should trigger when the default is used, but not when seq_cst is used explicitly (or implicitly as the failure order for cmpxchg). <rdar://problem/28172966> Reviewers: rjmccall Subscribers: dexonsmith, cfe-commits Differential Revision: https://reviews.llvm.org/D51084 llvm-svn: 341860
This commit is contained in:
parent
a5ae613c15
commit
e77b48b078
|
@ -7096,6 +7096,9 @@ def err_atomic_op_has_invalid_synch_scope : Error<
|
|||
def warn_atomic_op_misaligned : Warning<
|
||||
"%select{large|misaligned}0 atomic operation may incur "
|
||||
"significant performance penalty">, InGroup<DiagGroup<"atomic-alignment">>;
|
||||
def warn_atomic_implicit_seq_cst : Warning<
|
||||
"implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary">,
|
||||
InGroup<DiagGroup<"atomic-implicit-seq-cst">>, DefaultIgnore;
|
||||
|
||||
def err_overflow_builtin_must_be_int : Error<
|
||||
"operand argument to overflow builtin must be an integer (%0 invalid)">;
|
||||
|
|
|
@ -1134,6 +1134,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
|||
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);
|
||||
|
@ -4646,25 +4650,24 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
|
|||
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<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
|
||||
CallExpr *TheCall = static_cast<CallExpr *>(TheCallResult.get());
|
||||
Expr *Callee = TheCall->getCallee();
|
||||
DeclRefExpr *DRE = cast<DeclRefExpr>(Callee->IgnoreParenCasts());
|
||||
FunctionDecl *FDecl = cast<FunctionDecl>(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();
|
||||
}
|
||||
|
||||
|
@ -4941,13 +4944,16 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
|
|||
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
|
||||
|
@ -10284,6 +10290,10 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
|
|||
}
|
||||
|
||||
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.
|
||||
|
@ -10419,6 +10429,9 @@ static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
|
|||
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<BuiltinType>();
|
||||
const auto *RBT = cast<CompoundAssignOperator>(E)
|
||||
|
@ -10680,6 +10693,9 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
|
|||
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<StringLiteral>(E))
|
||||
|
@ -10975,11 +10991,13 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -11024,8 +11042,10 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
|
|||
}
|
||||
|
||||
// Skip past explicit casts.
|
||||
if (isa<ExplicitCastExpr>(E)) {
|
||||
E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
|
||||
if (auto *CE = dyn_cast<ExplicitCastExpr>(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);
|
||||
}
|
||||
|
||||
|
@ -11078,9 +11098,15 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
|
|||
::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc());
|
||||
}
|
||||
|
||||
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E))
|
||||
if (U->getOpcode() == UO_LNot)
|
||||
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(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.
|
||||
|
|
|
@ -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; }
|
|
@ -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}}
|
Loading…
Reference in New Issue