diff options
author | Fangrui Song <i@maskray.me> | 2023-12-14 11:03:28 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-14 11:03:28 -0800 |
commit | fed564432cef76f8b303c19ab1dfc0a14878fbc3 (patch) | |
tree | ffa392c614b3c37bfc7a30f962395e28642f5d9b /clang/lib/Sema/SemaChecking.cpp | |
parent | 419c45a3252489d0ebac4535fe5a4ed9a6af6bbd (diff) | |
download | llvm-fed564432cef76f8b303c19ab1dfc0a14878fbc3.zip llvm-fed564432cef76f8b303c19ab1dfc0a14878fbc3.tar.gz llvm-fed564432cef76f8b303c19ab1dfc0a14878fbc3.tar.bz2 |
[Sema] atomic_compare_exchange: check failure memory order (#74959)
For
`__atomic_compare_exchange{,_n}/__c11_atomic_compare_exchange_{strong,weak}`,
GCC checks both the success memory order and the failure memory order
under the default -Winvalid-memory-model ("memory model" is confusing
here and "memory order" is much more common in the atomic context).
* The failure memory order, if a constant, must be one of
relaxed/consume/acquire/seq_cst.
Clang checks just the success memory order under the default
-Watomic-memory-ordering. This patch checks the failure memory order.
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 254c272..bcddaa1 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5030,14 +5030,14 @@ bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, if (!llvm::isValidAtomicOrderingCABI(Ord)) return Diag(ArgExpr->getBeginLoc(), diag::warn_atomic_op_has_invalid_memory_order) - << ArgExpr->getSourceRange(); + << 0 << ArgExpr->getSourceRange(); switch (static_cast<llvm::AtomicOrderingCABI>(Ord)) { case llvm::AtomicOrderingCABI::relaxed: case llvm::AtomicOrderingCABI::consume: if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence) return Diag(ArgExpr->getBeginLoc(), diag::warn_atomic_op_has_invalid_memory_order) - << ArgExpr->getSourceRange(); + << 0 << ArgExpr->getSourceRange(); break; case llvm::AtomicOrderingCABI::acquire: case llvm::AtomicOrderingCABI::release: @@ -8177,13 +8177,31 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, break; } + // If the memory orders are constants, check they are valid. if (SubExprs.size() >= 2 && Form != Init) { - if (std::optional<llvm::APSInt> Result = - SubExprs[1]->getIntegerConstantExpr(Context)) - if (!isValidOrderingForOp(Result->getSExtValue(), Op)) - Diag(SubExprs[1]->getBeginLoc(), - diag::warn_atomic_op_has_invalid_memory_order) - << SubExprs[1]->getSourceRange(); + std::optional<llvm::APSInt> Success = + SubExprs[1]->getIntegerConstantExpr(Context); + if (Success && !isValidOrderingForOp(Success->getSExtValue(), Op)) { + Diag(SubExprs[1]->getBeginLoc(), + diag::warn_atomic_op_has_invalid_memory_order) + << /*success=*/(Form == C11CmpXchg || Form == GNUCmpXchg) + << SubExprs[1]->getSourceRange(); + } + if (SubExprs.size() >= 5) { + if (std::optional<llvm::APSInt> Failure = + SubExprs[3]->getIntegerConstantExpr(Context)) { + if (!llvm::is_contained( + {llvm::AtomicOrderingCABI::relaxed, + llvm::AtomicOrderingCABI::consume, + llvm::AtomicOrderingCABI::acquire, + llvm::AtomicOrderingCABI::seq_cst}, + (llvm::AtomicOrderingCABI)Failure->getSExtValue())) { + Diag(SubExprs[3]->getBeginLoc(), + diag::warn_atomic_op_has_invalid_memory_order) + << /*failure=*/2 << SubExprs[3]->getSourceRange(); + } + } + } } if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { |