================
@@ -4860,6 +4924,404 @@ static CompleteObject findCompleteObject(EvalInfo 
&Info, const Expr *E,
   return CompleteObject(LVal.getLValueBase(), BaseVal, BaseType);
 }
 
+static const APValue *GetArrayInitializedElt(const APValue &Array,
+                                             uint64_t Index) {
+  if (!Array.isArray() || Index >= Array.getArraySize())
+    return nullptr;
+  if (Index < Array.getArrayInitializedElts())
+    return &Array.getArrayInitializedElt(Index);
+  return Array.hasArrayFiller() ? &Array.getArrayFiller() : nullptr;
+}
+
+namespace {
+
+/// Combine a per-field result into an aggregate result. Models the lattice
+/// Equal < Unknown < NotEqual, where NotEqual absorbs and Equal is the
+/// identity. Callers may short-circuit on NotEqual.
+APValueEquality joinAPValueEquality(APValueEquality A, APValueEquality B) {
+  if (A == APValueEquality::NotEqual || B == APValueEquality::NotEqual)
+    return APValueEquality::NotEqual;
+  if (A == APValueEquality::Unknown || B == APValueEquality::Unknown)
+    return APValueEquality::Unknown;
+  return APValueEquality::Equal;
+}
+
+APValueEquality fromBoolEquality(bool Eq) {
+  return Eq ? APValueEquality::Equal : APValueEquality::NotEqual;
+}
+
+/// Return true if \p B names a program entity whose address is guaranteed
+/// distinct from any unrelated entity's address.
+bool isUniquelyAddressedBase(APValue::LValueBase B) {
+  if (const auto *VD = B.dyn_cast<const ValueDecl *>()) {
+    if (const auto *Var = dyn_cast<VarDecl>(VD))
+      return Var->hasGlobalStorage() && !Var->isWeak();
+    if (const auto *Fn = dyn_cast<FunctionDecl>(VD))
+      return !Fn->isWeak();
+    // Each LifetimeExtendedTemporaryDecl names a distinct storage instance.
+    if (isa<LifetimeExtendedTemporaryDecl>(VD))
+      return true;
+    return false;
+  }
+  // typeid objects and dynamic allocations are uniquely addressed in the
+  // abstract machine.
+  return B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>();
+}
+
+APValueEquality compareAddrLabelDiff(const APValue &LHS, const APValue &RHS) {
+  if (!LHS.isAddrLabelDiff() || !RHS.isAddrLabelDiff())
+    return APValueEquality::Unknown;
+  // &&label values are not constant - their runtime difference is only
+  // determined if both endpoints refer to the same labels.
+  if (LHS.getAddrLabelDiffLHS() == RHS.getAddrLabelDiffLHS() &&
+      LHS.getAddrLabelDiffRHS() == RHS.getAddrLabelDiffRHS())
+    return APValueEquality::Equal;
+  return APValueEquality::Unknown;
+}
+
+APValueEquality compareLValues(const APValue &LHS, const APValue &RHS,
+                               const ASTContext &Ctx) {
+  if (!LHS.isLValue() || !RHS.isLValue())
+    return APValueEquality::Unknown;
+
+  bool LHSIsNull = LHS.isNullPointer();
+  bool RHSIsNull = RHS.isNullPointer();
+  if (LHSIsNull != RHSIsNull)
+    return APValueEquality::NotEqual;
+  if (LHSIsNull)
+    return APValueEquality::Equal;
+
+  APValue::LValueBase LB = LHS.getLValueBase();
+  APValue::LValueBase RB = RHS.getLValueBase();
+
+  if (LB == RB) {
+    // Same program entity, same evaluation instance. The address is fully
+    // determined by the byte offset within the object. One-past-the-end
+    // pointers, however, may compare equal to the start of an adjacent
+    // object, so we can't claim either Equal or NotEqual when only one
+    // side is one-past-the-end.
+    if (LHS.isLValueOnePastTheEnd() != RHS.isLValueOnePastTheEnd())
+      return APValueEquality::Unknown;
+    return fromBoolEquality(LHS.getLValueOffset() == RHS.getLValueOffset());
+  }
+
+  if (std::optional<bool> PotentiallyOverlapping =
+          ArePotentiallyOverlappingStringLiterals(Ctx, LHS, RHS))
+    return *PotentiallyOverlapping ? APValueEquality::Unknown
+                                   : APValueEquality::NotEqual;
+
+  // Distinct, uniquely-addressed entities have distinct addresses - unless
+  // one of the operands is one-past-the-end, which is permitted to alias
+  // the start of another object.
+  if (isUniquelyAddressedBase(LB) && isUniquelyAddressedBase(RB) &&
+      !LHS.isLValueOnePastTheEnd() && !RHS.isLValueOnePastTheEnd())
+    return APValueEquality::NotEqual;
+
+  return APValueEquality::Unknown;
+}
+
+APValueEquality compareMemberPointers(const APValue &LHS, const APValue &RHS) {
+  if (!LHS.isMemberPointer() || !RHS.isMemberPointer())
+    return APValueEquality::Unknown;
+
+  const ValueDecl *LD = LHS.getMemberPointerDecl();
+  const ValueDecl *RD = RHS.getMemberPointerDecl();
+  if (!LD != !RD)
+    return APValueEquality::NotEqual;
+  if (!LD)
+    return APValueEquality::Equal;
+  if (LD->getCanonicalDecl() != RD->getCanonicalDecl()) {
+    // Distinct weak decls may resolve to the same merged target at link time.
+    if (LD->isWeak() || RD->isWeak())
+      return APValueEquality::Unknown;
+    return APValueEquality::NotEqual;
+  }
+
+  // A member pointer's value is fully determined by its target decl plus
+  // the path of derived-to-base / base-to-derived adjustments.
+  ArrayRef<const CXXRecordDecl *> LP = LHS.getMemberPointerPath();
+  ArrayRef<const CXXRecordDecl *> RP = RHS.getMemberPointerPath();
+  if (LP.size() != RP.size())
+    return APValueEquality::NotEqual;
+  for (auto [LE, RE] : llvm::zip_equal(LP, RP))
+    if (LE->getCanonicalDecl() != RE->getCanonicalDecl())
+      return APValueEquality::NotEqual;
+  return APValueEquality::Equal;
+}
+
+APValueEquality compareArrays(const ArrayType *AT, const APValue &LHS,
+                              const APValue &RHS, const ASTContext &Ctx);
+APValueEquality compareRecords(const RecordDecl *RD, const APValue &LHS,
+                               const APValue &RHS, const ASTContext &Ctx);
+APValueEquality compareComplex(const APValue &LHS, const APValue &RHS);
+APValueEquality compareVector(const APValue &LHS, const APValue &RHS,
+                              QualType EltTy, const ASTContext &Ctx);
+APValueEquality compareMatrix(const MatrixType *MT, const APValue &LHS,
+                              const APValue &RHS, const ASTContext &Ctx);
+
+} // namespace
+
+APValueEquality compareAPValues(QualType T, const APValue &LHS,
+                                const APValue &RHS, const ASTContext &Ctx) {
+  // The wrapped value is what's observable through an atomic type.
+  if (const auto *AT = T->getAs<AtomicType>())
+    T = AT->getValueType();
+
+  T = T.getCanonicalType();
+
+  // Volatile objects have implementation-defined reads, so even if both
+  // APValues currently hold the same bits we cannot prove the runtime
+  // values would be observably equal.
+  if (T.isVolatileQualified())
+    return APValueEquality::Unknown;
+
+  // A value flagged as "constexpr-unknown" carries no determinate content.
+  if (LHS.allowConstexprUnknown() || RHS.allowConstexprUnknown())
+    return APValueEquality::Unknown;
+
+  if (!LHS.hasValue() || !RHS.hasValue())
+    return APValueEquality::Unknown;
+
+  // std::nullptr_t has exactly one value, so any two operands are equal.
+  if (T->isNullPtrType())
+    return APValueEquality::Equal;
+
+  // Compound and pointer-like types - dispatch before checking kinds because
+  // null pointers and member pointers have distinct APValue representations.
+  if (T->isReferenceType() || T->isPointerType())
+    return compareLValues(LHS, RHS, Ctx);
+  if (T->isMemberPointerType())
+    return compareMemberPointers(LHS, RHS);
+  if (const ArrayType *AT = Ctx.getAsArrayType(T))
+    return compareArrays(AT, LHS, RHS, Ctx);
+  if (const RecordDecl *RD = T->getAsRecordDecl())
+    return compareRecords(RD, LHS, RHS, Ctx);
+  if (T->isAnyComplexType())
+    return compareComplex(LHS, RHS);
+  if (const auto *VT = T->getAs<VectorType>())
+    return compareVector(LHS, RHS, VT->getElementType(), Ctx);
+  if (const auto *MT = T->getAs<MatrixType>())
+    return compareMatrix(MT, LHS, RHS, Ctx);
+
+  // Scalar leaf: both sides must have the same kind.
+  if (LHS.getKind() != RHS.getKind())
+    return APValueEquality::NotEqual;
+
+  if (LHS.isInt())
+    return fromBoolEquality(LHS.getInt() == RHS.getInt());
+
+  // Bitwise comparison: -0.0 / +0.0 and NaN payloads are observable via
+  // signbit / memcmp, so the "indistinguishable" relation is bitwise.
+  if (LHS.isFloat())
+    return fromBoolEquality(LHS.getFloat().bitwiseIsEqual(RHS.getFloat()));
+
+  if (LHS.isFixedPoint())
+    return fromBoolEquality(LHS.getFixedPoint() == RHS.getFixedPoint());
+
+  // &&label values: the runtime address of a label isn't constant, so two
+  // diffs are only provably equal when they share both endpoints.
+  if (LHS.isAddrLabelDiff())
+    return compareAddrLabelDiff(LHS, RHS);
+
+  // Any APValue kind we don't explicitly model is conservatively unknown.
+  return APValueEquality::Unknown;
+}
+
+namespace {
+
+APValueEquality compareArrays(const ArrayType *AT, const APValue &LHS,
+                              const APValue &RHS, const ASTContext &Ctx) {
+  if (!LHS.isArray() || !RHS.isArray())
+    return APValueEquality::Unknown;
+  if (LHS.getArraySize() != RHS.getArraySize())
+    return APValueEquality::NotEqual;
+
+  QualType ElementType = AT->getElementType();
+  APValueEquality Result = APValueEquality::Equal;
+  for (uint64_t I = 0, N = LHS.getArraySize(); I != N; ++I) {
+    const APValue *LHSElt = GetArrayInitializedElt(LHS, I);
+    const APValue *RHSElt = GetArrayInitializedElt(RHS, I);
+    if (!LHSElt || !RHSElt)
+      return APValueEquality::Unknown;
+    Result = joinAPValueEquality(
+        Result, compareAPValues(ElementType, *LHSElt, *RHSElt, Ctx));
+    if (Result == APValueEquality::NotEqual)
+      return Result;
+  }
+  return Result;
+}
+
+APValueEquality compareRecords(const RecordDecl *RD, const APValue &LHS,
+                               const APValue &RHS, const ASTContext &Ctx) {
+  if (const RecordDecl *Definition = RD->getDefinition())
+    RD = Definition;
+
+  if (RD->isUnion()) {
+    if (!LHS.isUnion() || !RHS.isUnion())
+      return APValueEquality::Unknown;
----------------
cor3ntin wrote:

Can this happen?

https://github.com/llvm/llvm-project/pull/197458
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to