diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | 304 |
1 files changed, 182 insertions, 122 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 2d4dfae1e750..1017dff2b0f3 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <iterator> +#include <optional> using namespace clang; using namespace ento; @@ -913,20 +914,20 @@ namespace { class EquivalenceClass : public llvm::FoldingSetNode { public: /// Find equivalence class for the given symbol in the given state. - LLVM_NODISCARD static inline EquivalenceClass find(ProgramStateRef State, - SymbolRef Sym); + [[nodiscard]] static inline EquivalenceClass find(ProgramStateRef State, + SymbolRef Sym); /// Merge classes for the given symbols and return a new state. - LLVM_NODISCARD static inline ProgramStateRef merge(RangeSet::Factory &F, - ProgramStateRef State, - SymbolRef First, - SymbolRef Second); + [[nodiscard]] static inline ProgramStateRef merge(RangeSet::Factory &F, + ProgramStateRef State, + SymbolRef First, + SymbolRef Second); // Merge this class with the given class and return a new state. - LLVM_NODISCARD inline ProgramStateRef + [[nodiscard]] inline ProgramStateRef merge(RangeSet::Factory &F, ProgramStateRef State, EquivalenceClass Other); /// Return a set of class members for the given state. - LLVM_NODISCARD inline SymbolSet getClassMembers(ProgramStateRef State) const; + [[nodiscard]] inline SymbolSet getClassMembers(ProgramStateRef State) const; /// Return true if the current class is trivial in the given state. /// A class is trivial if and only if there is not any member relations stored @@ -939,43 +940,42 @@ public: /// members and then during the removal of dead symbols we remove one of its /// members. In this case, the class is still non-trivial (it still has the /// mappings in ClassMembers), even though it has only one member. - LLVM_NODISCARD inline bool isTrivial(ProgramStateRef State) const; + [[nodiscard]] inline bool isTrivial(ProgramStateRef State) const; /// Return true if the current class is trivial and its only member is dead. - LLVM_NODISCARD inline bool isTriviallyDead(ProgramStateRef State, - SymbolReaper &Reaper) const; + [[nodiscard]] inline bool isTriviallyDead(ProgramStateRef State, + SymbolReaper &Reaper) const; - LLVM_NODISCARD static inline ProgramStateRef + [[nodiscard]] static inline ProgramStateRef markDisequal(RangeSet::Factory &F, ProgramStateRef State, SymbolRef First, SymbolRef Second); - LLVM_NODISCARD static inline ProgramStateRef + [[nodiscard]] static inline ProgramStateRef markDisequal(RangeSet::Factory &F, ProgramStateRef State, EquivalenceClass First, EquivalenceClass Second); - LLVM_NODISCARD inline ProgramStateRef + [[nodiscard]] inline ProgramStateRef markDisequal(RangeSet::Factory &F, ProgramStateRef State, EquivalenceClass Other) const; - LLVM_NODISCARD static inline ClassSet - getDisequalClasses(ProgramStateRef State, SymbolRef Sym); - LLVM_NODISCARD inline ClassSet - getDisequalClasses(ProgramStateRef State) const; - LLVM_NODISCARD inline ClassSet + [[nodiscard]] static inline ClassSet getDisequalClasses(ProgramStateRef State, + SymbolRef Sym); + [[nodiscard]] inline ClassSet getDisequalClasses(ProgramStateRef State) const; + [[nodiscard]] inline ClassSet getDisequalClasses(DisequalityMapTy Map, ClassSet::Factory &Factory) const; - LLVM_NODISCARD static inline Optional<bool> areEqual(ProgramStateRef State, - EquivalenceClass First, - EquivalenceClass Second); - LLVM_NODISCARD static inline Optional<bool> + [[nodiscard]] static inline std::optional<bool> + areEqual(ProgramStateRef State, EquivalenceClass First, + EquivalenceClass Second); + [[nodiscard]] static inline std::optional<bool> areEqual(ProgramStateRef State, SymbolRef First, SymbolRef Second); /// Remove one member from the class. - LLVM_NODISCARD ProgramStateRef removeMember(ProgramStateRef State, - const SymbolRef Old); + [[nodiscard]] ProgramStateRef removeMember(ProgramStateRef State, + const SymbolRef Old); /// Iterate over all symbols and try to simplify them. - LLVM_NODISCARD static inline ProgramStateRef simplify(SValBuilder &SVB, - RangeSet::Factory &F, - ProgramStateRef State, - EquivalenceClass Class); + [[nodiscard]] static inline ProgramStateRef simplify(SValBuilder &SVB, + RangeSet::Factory &F, + ProgramStateRef State, + EquivalenceClass Class); void dumpToStream(ProgramStateRef State, raw_ostream &os) const; LLVM_DUMP_METHOD void dump(ProgramStateRef State) const { @@ -983,10 +983,10 @@ public: } /// Check equivalence data for consistency. - LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool + [[nodiscard]] LLVM_ATTRIBUTE_UNUSED static bool isClassDataConsistent(ProgramStateRef State); - LLVM_NODISCARD QualType getType() const { + [[nodiscard]] QualType getType() const { return getRepresentativeSymbol()->getType(); } @@ -1041,7 +1041,7 @@ private: // Constraint functions //===----------------------------------------------------------------------===// -LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED bool +[[nodiscard]] LLVM_ATTRIBUTE_UNUSED bool areFeasible(ConstraintRangeTy Constraints) { return llvm::none_of( Constraints, @@ -1050,24 +1050,24 @@ areFeasible(ConstraintRangeTy Constraints) { }); } -LLVM_NODISCARD inline const RangeSet *getConstraint(ProgramStateRef State, - EquivalenceClass Class) { +[[nodiscard]] inline const RangeSet *getConstraint(ProgramStateRef State, + EquivalenceClass Class) { return State->get<ConstraintRange>(Class); } -LLVM_NODISCARD inline const RangeSet *getConstraint(ProgramStateRef State, - SymbolRef Sym) { +[[nodiscard]] inline const RangeSet *getConstraint(ProgramStateRef State, + SymbolRef Sym) { return getConstraint(State, EquivalenceClass::find(State, Sym)); } -LLVM_NODISCARD ProgramStateRef setConstraint(ProgramStateRef State, - EquivalenceClass Class, - RangeSet Constraint) { +[[nodiscard]] ProgramStateRef setConstraint(ProgramStateRef State, + EquivalenceClass Class, + RangeSet Constraint) { return State->set<ConstraintRange>(Class, Constraint); } -LLVM_NODISCARD ProgramStateRef setConstraints(ProgramStateRef State, - ConstraintRangeTy Constraints) { +[[nodiscard]] ProgramStateRef setConstraints(ProgramStateRef State, + ConstraintRangeTy Constraints) { return State->set<ConstraintRange>(Constraints); } @@ -1084,7 +1084,7 @@ LLVM_NODISCARD ProgramStateRef setConstraints(ProgramStateRef State, /// \returns true if assuming this Sym to be true means equality of operands /// false if it means disequality of operands /// None otherwise -Optional<bool> meansEquality(const SymSymExpr *Sym) { +std::optional<bool> meansEquality(const SymSymExpr *Sym) { switch (Sym->getOpcode()) { case BO_Sub: // This case is: A - B != 0 -> disequality check. @@ -1096,7 +1096,7 @@ Optional<bool> meansEquality(const SymSymExpr *Sym) { // This case is: A != B != 0 -> diseqiality check. return false; default: - return llvm::None; + return std::nullopt; } } @@ -1105,8 +1105,8 @@ Optional<bool> meansEquality(const SymSymExpr *Sym) { //===----------------------------------------------------------------------===// template <class SecondTy, class... RestTy> -LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, - SecondTy Second, RestTy... Tail); +[[nodiscard]] inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, + SecondTy Second, RestTy... Tail); template <class... RangeTy> struct IntersectionTraits; @@ -1118,7 +1118,7 @@ template <class... TailTy> struct IntersectionTraits<RangeSet, TailTy...> { template <> struct IntersectionTraits<> { // We ran out of types, and we didn't find any RangeSet, so the result should // be optional. - using Type = Optional<RangeSet>; + using Type = std::optional<RangeSet>; }; template <class OptionalOrPointer, class... TailTy> @@ -1128,32 +1128,33 @@ struct IntersectionTraits<OptionalOrPointer, TailTy...> { }; template <class EndTy> -LLVM_NODISCARD inline EndTy intersect(RangeSet::Factory &F, EndTy End) { - // If the list contains only RangeSet or Optional<RangeSet>, simply return - // that range set. +[[nodiscard]] inline EndTy intersect(RangeSet::Factory &F, EndTy End) { + // If the list contains only RangeSet or std::optional<RangeSet>, simply + // return that range set. return End; } -LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED inline Optional<RangeSet> +[[nodiscard]] LLVM_ATTRIBUTE_UNUSED inline std::optional<RangeSet> intersect(RangeSet::Factory &F, const RangeSet *End) { - // This is an extraneous conversion from a raw pointer into Optional<RangeSet> + // This is an extraneous conversion from a raw pointer into + // std::optional<RangeSet> if (End) { return *End; } - return llvm::None; + return std::nullopt; } template <class... RestTy> -LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, - RangeSet Second, RestTy... Tail) { +[[nodiscard]] inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, + RangeSet Second, RestTy... Tail) { // Here we call either the <RangeSet,RangeSet,...> or <RangeSet,...> version // of the function and can be sure that the result is RangeSet. return intersect(F, F.intersect(Head, Second), Tail...); } template <class SecondTy, class... RestTy> -LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, - SecondTy Second, RestTy... Tail) { +[[nodiscard]] inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, + SecondTy Second, RestTy... Tail) { if (Second) { // Here we call the <RangeSet,RangeSet,...> version of the function... return intersect(F, Head, *Second, Tail...); @@ -1165,11 +1166,12 @@ LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, /// Main generic intersect function. /// It intersects all of the given range sets. If some of the given arguments -/// don't hold a range set (nullptr or llvm::None), the function will skip them. +/// don't hold a range set (nullptr or std::nullopt), the function will skip +/// them. /// /// Available representations for the arguments are: /// * RangeSet -/// * Optional<RangeSet> +/// * std::optional<RangeSet> /// * RangeSet * /// Pointer to a RangeSet is automatically assumed to be nullable and will get /// checked as well as the optional version. If this behaviour is undesired, @@ -1177,13 +1179,14 @@ LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head, /// /// Return type depends on the arguments' types. If we can be sure in compile /// time that there will be a range set as a result, the returning type is -/// simply RangeSet, in other cases we have to back off to Optional<RangeSet>. +/// simply RangeSet, in other cases we have to back off to +/// std::optional<RangeSet>. /// /// Please, prefer optional range sets to raw pointers. If the last argument is -/// a raw pointer and all previous arguments are None, it will cost one -/// additional check to convert RangeSet * into Optional<RangeSet>. +/// a raw pointer and all previous arguments are std::nullopt, it will cost one +/// additional check to convert RangeSet * into std::optional<RangeSet>. template <class HeadTy, class SecondTy, class... RestTy> -LLVM_NODISCARD inline +[[nodiscard]] inline typename IntersectionTraits<HeadTy, SecondTy, RestTy...>::Type intersect(RangeSet::Factory &F, HeadTy Head, SecondTy Second, RestTy... Tail) { @@ -1213,7 +1216,7 @@ public: } RangeSet VisitSymExpr(SymbolRef Sym) { - if (Optional<RangeSet> RS = getRangeForNegatedSym(Sym)) + if (std::optional<RangeSet> RS = getRangeForNegatedSym(Sym)) return *RS; // If we've reached this line, the actual type of the symbolic // expression is not supported for advanced inference. @@ -1223,7 +1226,7 @@ public: } RangeSet VisitUnarySymExpr(const UnarySymExpr *USE) { - if (Optional<RangeSet> RS = getRangeForNegatedUnarySym(USE)) + if (std::optional<RangeSet> RS = getRangeForNegatedUnarySym(USE)) return *RS; return infer(USE->getType()); } @@ -1333,18 +1336,7 @@ private: } RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op, - RangeSet RHS, QualType T) { - switch (Op) { - case BO_Or: - return VisitBinaryOperator<BO_Or>(LHS, RHS, T); - case BO_And: - return VisitBinaryOperator<BO_And>(LHS, RHS, T); - case BO_Rem: - return VisitBinaryOperator<BO_Rem>(LHS, RHS, T); - default: - return infer(T); - } - } + RangeSet RHS, QualType T); //===----------------------------------------------------------------------===// // Ranges and operators @@ -1362,11 +1354,11 @@ private: /// Try to convert given range into the given type. /// - /// It will return llvm::None only when the trivial conversion is possible. - llvm::Optional<Range> convert(const Range &Origin, APSIntType To) { + /// It will return std::nullopt only when the trivial conversion is possible. + std::optional<Range> convert(const Range &Origin, APSIntType To) { if (To.testInRange(Origin.From(), false) != APSIntType::RTR_Within || To.testInRange(Origin.To(), false) != APSIntType::RTR_Within) { - return llvm::None; + return std::nullopt; } return Range(ValueFactory.Convert(To, Origin.From()), ValueFactory.Convert(To, Origin.To())); @@ -1374,11 +1366,7 @@ private: template <BinaryOperator::Opcode Op> RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) { - // We should propagate information about unfeasbility of one of the - // operands to the resulting range. - if (LHS.isEmpty() || RHS.isEmpty()) { - return RangeFactory.getEmptySet(); - } + assert(!LHS.isEmpty() && !RHS.isEmpty()); Range CoarseLHS = fillGaps(LHS); Range CoarseRHS = fillGaps(RHS); @@ -1451,21 +1439,21 @@ private: } template <typename ProduceNegatedSymFunc> - Optional<RangeSet> getRangeForNegatedExpr(ProduceNegatedSymFunc F, - QualType T) { + std::optional<RangeSet> getRangeForNegatedExpr(ProduceNegatedSymFunc F, + QualType T) { // Do not negate if the type cannot be meaningfully negated. if (!T->isUnsignedIntegerOrEnumerationType() && !T->isSignedIntegerOrEnumerationType()) - return llvm::None; + return std::nullopt; if (SymbolRef NegatedSym = F()) if (const RangeSet *NegatedRange = getConstraint(State, NegatedSym)) return RangeFactory.negate(*NegatedRange); - return llvm::None; + return std::nullopt; } - Optional<RangeSet> getRangeForNegatedUnarySym(const UnarySymExpr *USE) { + std::optional<RangeSet> getRangeForNegatedUnarySym(const UnarySymExpr *USE) { // Just get the operand when we negate a symbol that is already negated. // -(-a) == a return getRangeForNegatedExpr( @@ -1477,7 +1465,7 @@ private: USE->getType()); } - Optional<RangeSet> getRangeForNegatedSymSym(const SymSymExpr *SSE) { + std::optional<RangeSet> getRangeForNegatedSymSym(const SymSymExpr *SSE) { return getRangeForNegatedExpr( [SSE, State = this->State]() -> SymbolRef { if (SSE->getOpcode() == BO_Sub) @@ -1488,7 +1476,7 @@ private: SSE->getType()); } - Optional<RangeSet> getRangeForNegatedSym(SymbolRef Sym) { + std::optional<RangeSet> getRangeForNegatedSym(SymbolRef Sym) { return getRangeForNegatedExpr( [Sym, State = this->State]() { return State->getSymbolManager().getUnarySymExpr(Sym, UO_Minus, @@ -1507,12 +1495,12 @@ private: // It covers all possible combinations (see CmpOpTable description). // Note that `x` and `y` can also stand for subexpressions, // not only for actual symbols. - Optional<RangeSet> getRangeForComparisonSymbol(const SymSymExpr *SSE) { + std::optional<RangeSet> getRangeForComparisonSymbol(const SymSymExpr *SSE) { const BinaryOperatorKind CurrentOP = SSE->getOpcode(); // We currently do not support <=> (C++20). if (!BinaryOperator::isComparisonOp(CurrentOP) || (CurrentOP == BO_Cmp)) - return llvm::None; + return std::nullopt; static const OperatorRelationsTable CmpOpTable{}; @@ -1582,16 +1570,16 @@ private: : getFalseRange(T); } - return llvm::None; + return std::nullopt; } - Optional<RangeSet> getRangeForEqualities(const SymSymExpr *Sym) { - Optional<bool> Equality = meansEquality(Sym); + std::optional<RangeSet> getRangeForEqualities(const SymSymExpr *Sym) { + std::optional<bool> Equality = meansEquality(Sym); if (!Equality) - return llvm::None; + return std::nullopt; - if (Optional<bool> AreEqual = + if (std::optional<bool> AreEqual = EquivalenceClass::areEqual(State, Sym->getLHS(), Sym->getRHS())) { // Here we cover two cases at once: // * if Sym is equality and its operands are known to be equal -> true @@ -1603,7 +1591,7 @@ private: return getFalseRange(Sym->getType()); } - return llvm::None; + return std::nullopt; } RangeSet getTrueRange(QualType T) { @@ -1626,6 +1614,57 @@ private: //===----------------------------------------------------------------------===// template <> +RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_NE>(RangeSet LHS, + RangeSet RHS, + QualType T) { + assert(!LHS.isEmpty() && !RHS.isEmpty()); + + if (LHS.getAPSIntType() == RHS.getAPSIntType()) { + if (intersect(RangeFactory, LHS, RHS).isEmpty()) + return getTrueRange(T); + + } else { + // We can only lose information if we are casting smaller signed type to + // bigger unsigned type. For e.g., + // LHS (unsigned short): [2, USHRT_MAX] + // RHS (signed short): [SHRT_MIN, 0] + // + // Casting RHS to LHS type will leave us with overlapping values + // CastedRHS : [0, 0] U [SHRT_MAX + 1, USHRT_MAX] + // + // We can avoid this by checking if signed type's maximum value is lesser + // than unsigned type's minimum value. + + // If both have different signs then only we can get more information. + if (LHS.isUnsigned() != RHS.isUnsigned()) { + if (LHS.isUnsigned() && (LHS.getBitWidth() >= RHS.getBitWidth())) { + if (RHS.getMaxValue().isNegative() || + LHS.getAPSIntType().convert(RHS.getMaxValue()) < LHS.getMinValue()) + return getTrueRange(T); + + } else if (RHS.isUnsigned() && (LHS.getBitWidth() <= RHS.getBitWidth())) { + if (LHS.getMaxValue().isNegative() || + RHS.getAPSIntType().convert(LHS.getMaxValue()) < RHS.getMinValue()) + return getTrueRange(T); + } + } + + // Both RangeSets should be casted to bigger unsigned type. + APSIntType CastingType(std::max(LHS.getBitWidth(), RHS.getBitWidth()), + LHS.isUnsigned() || RHS.isUnsigned()); + + RangeSet CastedLHS = RangeFactory.castTo(LHS, CastingType); + RangeSet CastedRHS = RangeFactory.castTo(RHS, CastingType); + + if (intersect(RangeFactory, CastedLHS, CastedRHS).isEmpty()) + return getTrueRange(T); + } + + // In all other cases, the resulting range cannot be deduced. + return infer(T); +} + +template <> RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Or>(Range LHS, Range RHS, QualType T) { APSIntType ResultType = ValueFactory.getAPSIntType(T); @@ -1785,6 +1824,29 @@ RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Rem>(Range LHS, return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)}; } +RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS, + BinaryOperator::Opcode Op, + RangeSet RHS, QualType T) { + // We should propagate information about unfeasbility of one of the + // operands to the resulting range. + if (LHS.isEmpty() || RHS.isEmpty()) { + return RangeFactory.getEmptySet(); + } + + switch (Op) { + case BO_NE: + return VisitBinaryOperator<BO_NE>(LHS, RHS, T); + case BO_Or: + return VisitBinaryOperator<BO_Or>(LHS, RHS, T); + case BO_And: + return VisitBinaryOperator<BO_And>(LHS, RHS, T); + case BO_Rem: + return VisitBinaryOperator<BO_Rem>(LHS, RHS, T); + default: + return infer(T); + } +} + //===----------------------------------------------------------------------===// // Constraint manager implementation details //===----------------------------------------------------------------------===// @@ -1995,7 +2057,7 @@ public: class ConstraintAssignor : public ConstraintAssignorBase<ConstraintAssignor> { public: template <class ClassOrSymbol> - LLVM_NODISCARD static ProgramStateRef + [[nodiscard]] static ProgramStateRef assign(ProgramStateRef State, SValBuilder &Builder, RangeSet::Factory &F, ClassOrSymbol CoS, RangeSet NewConstraint) { if (!State || NewConstraint.isEmpty()) @@ -2037,7 +2099,7 @@ private: using Base = ConstraintAssignorBase<ConstraintAssignor>; /// Base method for handling new constraints for symbols. - LLVM_NODISCARD ProgramStateRef assign(SymbolRef Sym, RangeSet NewConstraint) { + [[nodiscard]] ProgramStateRef assign(SymbolRef Sym, RangeSet NewConstraint) { // All constraints are actually associated with equivalence classes, and // that's what we are going to do first. State = assign(EquivalenceClass::find(State, Sym), NewConstraint); @@ -2051,8 +2113,8 @@ private: } /// Base method for handling new constraints for classes. - LLVM_NODISCARD ProgramStateRef assign(EquivalenceClass Class, - RangeSet NewConstraint) { + [[nodiscard]] ProgramStateRef assign(EquivalenceClass Class, + RangeSet NewConstraint) { // There is a chance that we might need to update constraints for the // classes that are known to be disequal to Class. // @@ -2098,7 +2160,7 @@ private: return EquivalenceClass::merge(RangeFactory, State, LHS, RHS); } - LLVM_NODISCARD Optional<bool> interpreteAsBool(RangeSet Constraint) { + [[nodiscard]] std::optional<bool> interpreteAsBool(RangeSet Constraint) { assert(!Constraint.isEmpty() && "Empty ranges shouldn't get here"); if (Constraint.getConcreteValue()) @@ -2107,7 +2169,7 @@ private: if (!Constraint.containsZero()) return true; - return llvm::None; + return std::nullopt; } ProgramStateRef State; @@ -2115,7 +2177,6 @@ private: RangeSet::Factory &RangeFactory; }; - bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym, const llvm::APSInt &Constraint) { llvm::SmallSet<EquivalenceClass, 4> SimplifiedClasses; @@ -2162,12 +2223,12 @@ bool ConstraintAssignor::assignSymSymExprToRangeSet(const SymSymExpr *Sym, if (!handleRemainderOp(Sym, Constraint)) return false; - Optional<bool> ConstraintAsBool = interpreteAsBool(Constraint); + std::optional<bool> ConstraintAsBool = interpreteAsBool(Constraint); if (!ConstraintAsBool) return true; - if (Optional<bool> Equality = meansEquality(Sym)) { + if (std::optional<bool> Equality = meansEquality(Sym)) { // Here we cover two cases: // * if Sym is equality and the new constraint is true -> Sym's operands // should be marked as equal @@ -2305,7 +2366,7 @@ EquivalenceClass::mergeImpl(RangeSet::Factory &RangeFactory, // // Intersection here makes perfect sense because both of these constraints // must hold for the whole new class. - if (Optional<RangeSet> NewClassConstraint = + if (std::optional<RangeSet> NewClassConstraint = intersect(RangeFactory, getConstraint(State, *this), getConstraint(State, Other))) { // NOTE: Essentially, NewClassConstraint should NEVER be infeasible because @@ -2503,16 +2564,16 @@ inline bool EquivalenceClass::addToDisequalityInfo( return true; } -inline Optional<bool> EquivalenceClass::areEqual(ProgramStateRef State, - SymbolRef FirstSym, - SymbolRef SecondSym) { +inline std::optional<bool> EquivalenceClass::areEqual(ProgramStateRef State, + SymbolRef FirstSym, + SymbolRef SecondSym) { return EquivalenceClass::areEqual(State, find(State, FirstSym), find(State, SecondSym)); } -inline Optional<bool> EquivalenceClass::areEqual(ProgramStateRef State, - EquivalenceClass First, - EquivalenceClass Second) { +inline std::optional<bool> EquivalenceClass::areEqual(ProgramStateRef State, + EquivalenceClass First, + EquivalenceClass Second) { // The same equivalence class => symbols are equal. if (First == Second) return true; @@ -2524,10 +2585,10 @@ inline Optional<bool> EquivalenceClass::areEqual(ProgramStateRef State, return false; // It is not clear. - return llvm::None; + return std::nullopt; } -LLVM_NODISCARD ProgramStateRef +[[nodiscard]] ProgramStateRef EquivalenceClass::removeMember(ProgramStateRef State, const SymbolRef Old) { SymbolSet ClsMembers = getClassMembers(State); @@ -2556,9 +2617,8 @@ EquivalenceClass::removeMember(ProgramStateRef State, const SymbolRef Old) { } // Re-evaluate an SVal with top-level `State->assume` logic. -LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State, - const RangeSet *Constraint, - SVal TheValue) { +[[nodiscard]] ProgramStateRef +reAssume(ProgramStateRef State, const RangeSet *Constraint, SVal TheValue) { if (!Constraint) return State; @@ -2587,7 +2647,7 @@ LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State, // class to this class. This way, we simplify not just the symbols but the // classes as well: we strive to keep the number of the classes to be the // absolute minimum. -LLVM_NODISCARD ProgramStateRef +[[nodiscard]] ProgramStateRef EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F, ProgramStateRef State, EquivalenceClass Class) { SymbolSet ClassMembers = Class.getClassMembers(State); @@ -2717,7 +2777,7 @@ bool EquivalenceClass::isClassDataConsistent(ProgramStateRef State) { //===----------------------------------------------------------------------===// bool RangeConstraintManager::canReasonAbout(SVal X) const { - Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>(); + std::optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>(); if (SymVal && SymVal->isExpression()) { const SymExpr *SE = SymVal->getSymbol(); |