[libcxx-commits] [clang] [libcxx] [clang] [libc++] P3309 constexpr atomic and atomic ref [WIP] (PR #98738)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Jul 13 04:04:10 PDT 2024
Hana =?utf-8?q?Dusíková?= <hanicka at hanicka.net>,
Hana =?utf-8?q?Dusíková?= <hanicka at hanicka.net>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/98738 at github.com>
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Hana Dusíková (hanickadot)
<details>
<summary>Changes</summary>
This implements P3309 `constexpr std::atomic & std::atomic_ref` (currently in LWG) by allowing constant evaluation of clang's `__c11_atomic_OP` and GCC's `__atomic_OP` builtins.
Implementation in library is then simple, just marking everything constexpr, in `atomic_ref` is used `if consteval` code forking to avoid `reinterpret_cast` which is there to avoid missing capability of GCC's atomic builtins which doesn't support operations on floats.
---
Patch is 97.83 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/98738.diff
7 Files Affected:
- (modified) clang/include/clang/Basic/Builtins.td (+42-42)
- (modified) clang/lib/AST/ExprConstant.cpp (+412)
- (modified) libcxx/include/__atomic/atomic.h (+49-40)
- (modified) libcxx/include/__atomic/atomic_base.h (+46-30)
- (modified) libcxx/include/__atomic/atomic_flag.h (+35-21)
- (modified) libcxx/include/__atomic/atomic_ref.h (+260-116)
- (modified) libcxx/include/__atomic/cxx_atomic_impl.h (+43-36)
``````````diff
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index f5b15cf90d1f8..0716cf02f5110 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1682,97 +1682,97 @@ def SyncSwapN : Builtin, SyncBuiltinsTemplate {
// C11 _Atomic operations for <stdatomic.h>.
def C11AtomicInit : AtomicBuiltin {
let Spellings = ["__c11_atomic_init"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicLoad : AtomicBuiltin {
let Spellings = ["__c11_atomic_load"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicStore : AtomicBuiltin {
let Spellings = ["__c11_atomic_store"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicExchange : AtomicBuiltin {
let Spellings = ["__c11_atomic_exchange"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicCompareExchangeStrong : AtomicBuiltin {
let Spellings = ["__c11_atomic_compare_exchange_strong"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicCompareExchangeWeak : AtomicBuiltin {
let Spellings = ["__c11_atomic_compare_exchange_weak"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchAdd : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_add"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchSub : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_sub"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchAnd : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_and"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchOr : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_or"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchXor : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_xor"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchNand : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_nand"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchMax : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_max"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicFetchMin : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_min"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def C11AtomicThreadFence : Builtin {
let Spellings = ["__c11_atomic_thread_fence"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}
def C11AtomicSignalFence : Builtin {
let Spellings = ["__c11_atomic_signal_fence"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}
@@ -1785,157 +1785,157 @@ def C11AtomicIsLockFree : Builtin {
// GNU atomic builtins.
def AtomicLoad : AtomicBuiltin {
let Spellings = ["__atomic_load"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicLoadN : AtomicBuiltin {
let Spellings = ["__atomic_load_n"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicStore : AtomicBuiltin {
let Spellings = ["__atomic_store"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicStoreN : AtomicBuiltin {
let Spellings = ["__atomic_store_n"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicExchange : AtomicBuiltin {
let Spellings = ["__atomic_exchange"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicExchangeN : AtomicBuiltin {
let Spellings = ["__atomic_exchange_n"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicCompareExchange : AtomicBuiltin {
let Spellings = ["__atomic_compare_exchange"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicCompareExchangeN : AtomicBuiltin {
let Spellings = ["__atomic_compare_exchange_n"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicFetchAdd : AtomicBuiltin {
let Spellings = ["__atomic_fetch_add"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicFetchSub : AtomicBuiltin {
let Spellings = ["__atomic_fetch_sub"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicFetchAnd : AtomicBuiltin {
let Spellings = ["__atomic_fetch_and"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicFetchOr : AtomicBuiltin {
let Spellings = ["__atomic_fetch_or"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicFetchXor : AtomicBuiltin {
let Spellings = ["__atomic_fetch_xor"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicFetchNand : AtomicBuiltin {
let Spellings = ["__atomic_fetch_nand"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicAddFetch : AtomicBuiltin {
let Spellings = ["__atomic_add_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicSubFetch : AtomicBuiltin {
let Spellings = ["__atomic_sub_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicAndFetch : AtomicBuiltin {
let Spellings = ["__atomic_and_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicOrFetch : AtomicBuiltin {
let Spellings = ["__atomic_or_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicXorFetch : AtomicBuiltin {
let Spellings = ["__atomic_xor_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicMaxFetch : AtomicBuiltin {
let Spellings = ["__atomic_max_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicMinFetch : AtomicBuiltin {
let Spellings = ["__atomic_min_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicNandFetch : AtomicBuiltin {
let Spellings = ["__atomic_nand_fetch"];
- let Attributes = [CustomTypeChecking];
+ let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def AtomicTestAndSet : Builtin {
let Spellings = ["__atomic_test_and_set"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "bool(void volatile*, int)";
}
def AtomicClear : Builtin {
let Spellings = ["__atomic_clear"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "void(void volatile*, int)";
}
def AtomicThreadFence : Builtin {
let Spellings = ["__atomic_thread_fence"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}
def AtomicSignalFence : Builtin {
let Spellings = ["__atomic_signal_fence"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 0aeac9d03eed3..2cb7de0ed747a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1900,6 +1900,9 @@ static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result,
// Misc utilities
//===----------------------------------------------------------------------===//
+static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx,
+ const LValue &LV);
+
/// Negate an APSInt in place, converting it to a signed form if necessary, and
/// preserving its value (by extending by up to one bit as needed).
static void negateAsSigned(APSInt &Int) {
@@ -7884,6 +7887,404 @@ class ExprEvaluatorBase
return StmtVisitorTy::Visit(Source);
}
+ static bool EvaluateOrder(const Expr *E, EvalInfo &Info) {
+ // we ignore order
+ [[maybe_unused]] APSInt Order;
+ if (!EvaluateInteger(E, Order, Info)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool ReadAtomicPtr(const AtomicExpr *E, APValue &Result,
+ EvalInfo &Info) {
+ LValue AtomicLV;
+ if (!EvaluatePointer(E->getPtr(), AtomicLV, Info)) {
+ return false;
+ }
+
+ if (!handleLValueToRValueConversion(Info, E->getPtr(), E->getType(),
+ AtomicLV, Result)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool LoadAtomicValue(const AtomicExpr *E, APValue &Result,
+ EvalInfo &Info) {
+ if (!ReadAtomicPtr(E, Result, Info)) {
+ return false;
+ }
+
+ // we ignore order
+ if (!EvaluateOrder(E->getOrder(), Info)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool FetchAtomicOp(const AtomicExpr *E, APValue &Result,
+ EvalInfo &Info, bool StoreToResultAfter) {
+ LValue AtomicLV;
+ QualType AtomicTy =
+ E->getPtr()->getType()->getPointeeType().getAtomicUnqualifiedType();
+ if (!EvaluatePointer(E->getPtr(), AtomicLV, Info)) {
+ return false;
+ }
+
+ APValue AtomicVal;
+ if (!handleLValueToRValueConversion(Info, E->getPtr(), E->getType(),
+ AtomicLV, AtomicVal)) {
+ return false;
+ }
+
+ if (!StoreToResultAfter) {
+ Result = AtomicVal;
+ }
+
+ const auto ResultType = E->getType();
+
+ APValue ArgumentVal;
+ if (!Evaluate(ArgumentVal, Info, E->getVal1())) {
+ return false;
+ }
+
+ APValue Replacement;
+ if (ResultType->isIntegralOrEnumerationType()) {
+ const APSInt AtomicInt = AtomicVal.getInt();
+ const APSInt ArgumentInt = ArgumentVal.getInt();
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__atomic_add_fetch:
+ Replacement = APValue(AtomicInt + ArgumentInt);
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_sub_fetch:
+ Replacement = APValue(AtomicInt - ArgumentInt);
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__atomic_and_fetch:
+ Replacement = APValue(AtomicInt & ArgumentInt);
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__atomic_or_fetch:
+ Replacement = APValue(AtomicInt | ArgumentInt);
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_xor_fetch:
+ Replacement = APValue(AtomicInt ^ ArgumentInt);
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_nand_fetch:
+ Replacement = APValue(~(AtomicInt & ArgumentInt));
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_max:
+ case AtomicExpr::AO__atomic_fetch_max:
+ case AtomicExpr::AO__atomic_max_fetch:
+ Replacement =
+ APValue((AtomicInt > ArgumentInt) ? AtomicInt : ArgumentInt);
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_min:
+ case AtomicExpr::AO__atomic_fetch_min:
+ case AtomicExpr::AO__atomic_min_fetch:
+ Replacement =
+ APValue((AtomicInt < ArgumentInt) ? AtomicInt : ArgumentInt);
+ break;
+ default:
+ return false;
+ }
+ } else if (ResultType->isRealFloatingType()) {
+ const llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
+ APFloat AtomicFlt = AtomicVal.getFloat();
+ const APFloat ArgumentFlt = ArgumentVal.getFloat();
+ APFloat::opStatus St;
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_fetch_add: // GCC atomics doesn't support floats
+ St = AtomicFlt.add(ArgumentFlt, RM);
+ Replacement = APValue(AtomicFlt);
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ St = AtomicFlt.subtract(ArgumentFlt, RM);
+ Replacement = APValue(AtomicFlt);
+ break;
+ default:
+ return false;
+ }
+
+ if (!checkFloatingPointResult(Info, E, St)) {
+ return false;
+ }
+ } else if (ResultType->isPointerType()) {
+ LValue AtomicPtr;
+ AtomicPtr.setFrom(Info.Ctx, AtomicVal);
+
+ APSInt ArgumentInt = ArgumentVal.getInt();
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__atomic_add_fetch:
+ if (!HandleLValueArrayAdjustment(
+ Info, E, AtomicPtr, AtomicTy->getPointeeType(), ArgumentInt)) {
+ return false;
+ }
+ break;
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_sub_fetch:
+ ArgumentInt.negate();
+ if (!HandleLValueArrayAdjustment(
+ Info, E, AtomicPtr, AtomicTy->getPointeeType(), ArgumentInt)) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ AtomicPtr.moveInto(Replacement);
+ } else {
+ // not float,int,pointer?
+ return false;
+ }
+
+ if (StoreToResultAfter) {
+ Result = Replacement;
+ }
+
+ if (!handleAssignment(Info, E, AtomicLV, AtomicTy, Replacement)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool StoreAtomicValue(const AtomicExpr *E, EvalInfo &Info) {
+ LValue LV;
+ if (!EvaluatePointer(E->getPtr(), LV, Info)) {
+ return false;
+ }
+
+ APValue NewVal;
+ if (!Evaluate(NewVal, Info, E->getVal1())) {
+ return false;
+ }
+
+ if (!handleAssignment(Info, E, LV, E->getVal1()->getType(), NewVal)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool CompareExchangeAtomicValue(const AtomicExpr *E, APValue &Result,
+ EvalInfo &Info) {
+ // dereference _Atomic * (atomic value)
+ LValue AtomicLV;
+ QualType AtomicTy =
+ E->getPtr()->getType()->getPointeeType().getAtomicUnqualifiedType();
+ if (!EvaluatePointer(E->getPtr(), AtomicLV, Info)) {
+ return false;
+ }
+
+ // dereference T * (expected value)
+ LValue ExpectedLV;
+ QualType ExpectedTy = E->getVal1()->getType()->getPointeeType();
+ if (!EvaluatePointer(E->getVal1(), ExpectedLV, Info)) {
+ return false;
+ }
+
+ // get values for atomic and expected
+ APValue AtomicVal;
+ APValue ExpectedVal;
+
+ // convert pointer to value
+ if (!handleLValueToRValueConversion(Info, E->getPtr(), AtomicTy, AtomicLV,
+ AtomicVal)) {
+ return false;
+ }
+
+ if (!handleLValueToRValueConversion(Info, E->getVal1(), ExpectedTy,
+ ExpectedLV, ExpectedVal)) {
+ return false;
+ }
+
+ bool DoExchange = false;
+
+ // compare atomic<int> and friends
+ if (AtomicTy->isIntegralOrEnumerationType() &&
+ ExpectedTy->isIntegralOrEnumerationType()) {
+ const APSInt AtomicInt = AtomicVal.getInt();
+ const APSInt ExpectedInt = ExpectedVal.getInt();
+ if (AtomicInt == ExpectedInt) {
+ DoExchange = true;
+ }
+ } else if (AtomicTy->isRealFloatingType() &&
+ ExpectedTy->isRealFloatingType()) {
+ const APFloat AtomicFlt = AtomicVal.getFloat();
+ const APFloat ExpectedFlt = ExpectedVal.getFloat();
+ if (AtomicFlt == ExpectedFlt) {
+ DoExchange = true;
+ }
+ } else if (AtomicTy->isPointerType() && ExpectedTy->isPointerType()) {
+ // get LValue of objects pointed to
+ LValue LHS;
+ LHS.setFrom(Info.Ctx, AtomicVal);
+
+ LValue RHS;
+ RHS.setFrom(Info.Ctx, ExpectedVal);
+
+ if (HasSameBase(LHS, RHS)) {
+ const CharUnits &LHSOffset = LHS.getLValueOffset();
+ const CharUnits &RHSOffset = RHS.getLValueOffset();
+
+ const unsigned PtrSize = Info.Ctx.getTypeSize(AtomicTy);
+ assert(PtrSize <= 64 && "Pointer width is larger than expected");
+ const uint64_t Mask = ~0ULL >> (64 - PtrSize);
+
+ const uint64_t CompareLHS = LHSOffset.getQuantity() & Mask;
+ const uint64_t CompareRHS = RHSOffset.getQuantity() & Mask;
+
+ if (CompareLHS == CompareRHS) {
+ DoExchange = true;
+ }
+ } else {
+
+ // it's implementation-defined to compare distinct literals
+ // it's not constant-evaluation
+ if ((IsLiteralLValue(LHS) || IsLiteralLValue(RHS)) && LHS.Base &&
+ RHS.Base) {
+ return false;
+ }
+
+ if (IsWeakLValue(LHS) || IsWeakLValue(RHS)) {
+ return false;
+ }
+
+ if ((!LHS.Base && !LHS.Offset.isZero()) ||
+ (!RHS.Base && !RHS.Offset.isZero())) {
+ return false;
+ }
+
+ if (LHS.Base && LHS.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, RHS)) {
+ return false;
+ }
+
+ if (RHS.Base && RHS.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHS)) {
+ return false;
+ }
+
+ if ((RHS.Base && isZeroSized(RHS)) || (LHS.Base && isZeroSized(LHS))) {
+ return false;
+ }
+
+ // after all it's a different object
+ DoExchange = false;
+ }
+
+ } else {
+ return false;
+ }
+
+ if (DoExchange) {
+ // if values are same do the exchange with replacement value
+ // but first I must evaluate the replacement value
+ APValue Replacement;
+ if (!Evaluate(Replacement, Info, E->getVal2())) {
+ return false;
+ }
+
+ // and assign it to atomic
+ if (!handleAssignment(Info, E, AtomicLV, AtomicTy, Replacement)) {
+ return false;
+ }
+ }
+
+ // to expected p...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/98738
More information about the libcxx-commits
mailing list