martong created this revision. martong added reviewers: NoQ, steakhal. Herald added subscribers: manas, ASDenysPetrov, gamesh411, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun. Herald added a reviewer: Szelethus. Herald added a project: All. martong requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Depends on D125892 <https://reviews.llvm.org/D125892>. There might be efficiency and performance implications by using a lambda. Thus, I am going to conduct measurements to see if there is any noticeable impact. I've been thinking about two more alternatives: 1. Make `assumeDualImpl` a variadic template and (perfect) forward the arguments for the used `assume` function. 2. Use a macros. I have concerns though, whether these alternatives would deteriorate the readability of the code. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D125954 Files: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp Index: clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp +++ clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp @@ -42,12 +42,14 @@ return {}; } +template <typename AssumeFunction> ConstraintManager::ProgramStatePair -ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) { - ProgramStateRef StTrue = assumeInternal(State, Cond, true); +ConstraintManager::assumeDualImpl(ProgramStateRef &State, + AssumeFunction &Assume) { + ProgramStateRef StTrue = Assume(true); if (!StTrue) { - ProgramStateRef StFalse = assumeInternal(State, Cond, false); + ProgramStateRef StFalse = Assume(false); if (LLVM_UNLIKELY(!StFalse)) { // both infeasible ProgramStateRef StInfeasible = State->cloneAsPosteriorlyOverconstrained(); assert(StInfeasible->isPosteriorlyOverconstrained()); @@ -63,7 +65,7 @@ return ProgramStatePair(nullptr, StFalse); } - ProgramStateRef StFalse = assumeInternal(State, Cond, false); + ProgramStateRef StFalse = Assume(false); if (!StFalse) { return ProgramStatePair(StTrue, nullptr); } @@ -71,36 +73,22 @@ return ProgramStatePair(StTrue, StFalse); } +ConstraintManager::ProgramStatePair +ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) { + auto AssumeFun = [&](bool Assumption) { + return assumeInternal(State, Cond, Assumption); + }; + return assumeDualImpl(State, AssumeFun); +} + ConstraintManager::ProgramStatePair ConstraintManager::assumeInclusiveRangeDual(ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, const llvm::APSInt &To) { - ProgramStateRef StInRange = - assumeInclusiveRangeInternal(State, Value, From, To, true); - if (!StInRange) { - ProgramStateRef StOutOfRange = - assumeInclusiveRangeInternal(State, Value, From, To, false); - if (LLVM_UNLIKELY(!StOutOfRange)) { // both infeasible - ProgramStateRef StInfeasible = State->cloneAsPosteriorlyOverconstrained(); - assert(StInfeasible->isPosteriorlyOverconstrained()); - // Checkers might rely on the API contract that both returned states - // cannot be null. Thus, we return StInfeasible for both branches because - // it might happen that a Checker uncoditionally uses one of them if the - // other is a nullptr. This may also happen with the non-dual and - // adjacent `assume(true)` and `assume(false)` calls. By implementing - // assume in therms of assumeDual, we can keep our API contract there as - // well. - return ProgramStatePair(StInfeasible, StInfeasible); - } - } - - ProgramStateRef StOutOfRange = - assumeInclusiveRangeInternal(State, Value, From, To, false); - if (!StOutOfRange) { - return ProgramStatePair(StInRange, nullptr); - } - - return ProgramStatePair(StInRange, StOutOfRange); + auto AssumeFun = [&](bool Assumption) { + return assumeInclusiveRangeInternal(State, Value, From, To, Assumption); + }; + return assumeDualImpl(State, AssumeFun); } ProgramStateRef ConstraintManager::assume(ProgramStateRef State, Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -162,6 +162,10 @@ /// Returns whether or not a symbol is known to be null ("true"), known to be /// non-null ("false"), or may be either ("underconstrained"). virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); + + template <typename AssumeFunction> + ProgramStatePair assumeDualImpl(ProgramStateRef &State, + AssumeFunction &Assume); }; std::unique_ptr<ConstraintManager>
Index: clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp +++ clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp @@ -42,12 +42,14 @@ return {}; } +template <typename AssumeFunction> ConstraintManager::ProgramStatePair -ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) { - ProgramStateRef StTrue = assumeInternal(State, Cond, true); +ConstraintManager::assumeDualImpl(ProgramStateRef &State, + AssumeFunction &Assume) { + ProgramStateRef StTrue = Assume(true); if (!StTrue) { - ProgramStateRef StFalse = assumeInternal(State, Cond, false); + ProgramStateRef StFalse = Assume(false); if (LLVM_UNLIKELY(!StFalse)) { // both infeasible ProgramStateRef StInfeasible = State->cloneAsPosteriorlyOverconstrained(); assert(StInfeasible->isPosteriorlyOverconstrained()); @@ -63,7 +65,7 @@ return ProgramStatePair(nullptr, StFalse); } - ProgramStateRef StFalse = assumeInternal(State, Cond, false); + ProgramStateRef StFalse = Assume(false); if (!StFalse) { return ProgramStatePair(StTrue, nullptr); } @@ -71,36 +73,22 @@ return ProgramStatePair(StTrue, StFalse); } +ConstraintManager::ProgramStatePair +ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) { + auto AssumeFun = [&](bool Assumption) { + return assumeInternal(State, Cond, Assumption); + }; + return assumeDualImpl(State, AssumeFun); +} + ConstraintManager::ProgramStatePair ConstraintManager::assumeInclusiveRangeDual(ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, const llvm::APSInt &To) { - ProgramStateRef StInRange = - assumeInclusiveRangeInternal(State, Value, From, To, true); - if (!StInRange) { - ProgramStateRef StOutOfRange = - assumeInclusiveRangeInternal(State, Value, From, To, false); - if (LLVM_UNLIKELY(!StOutOfRange)) { // both infeasible - ProgramStateRef StInfeasible = State->cloneAsPosteriorlyOverconstrained(); - assert(StInfeasible->isPosteriorlyOverconstrained()); - // Checkers might rely on the API contract that both returned states - // cannot be null. Thus, we return StInfeasible for both branches because - // it might happen that a Checker uncoditionally uses one of them if the - // other is a nullptr. This may also happen with the non-dual and - // adjacent `assume(true)` and `assume(false)` calls. By implementing - // assume in therms of assumeDual, we can keep our API contract there as - // well. - return ProgramStatePair(StInfeasible, StInfeasible); - } - } - - ProgramStateRef StOutOfRange = - assumeInclusiveRangeInternal(State, Value, From, To, false); - if (!StOutOfRange) { - return ProgramStatePair(StInRange, nullptr); - } - - return ProgramStatePair(StInRange, StOutOfRange); + auto AssumeFun = [&](bool Assumption) { + return assumeInclusiveRangeInternal(State, Value, From, To, Assumption); + }; + return assumeDualImpl(State, AssumeFun); } ProgramStateRef ConstraintManager::assume(ProgramStateRef State, Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -162,6 +162,10 @@ /// Returns whether or not a symbol is known to be null ("true"), known to be /// non-null ("false"), or may be either ("underconstrained"). virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); + + template <typename AssumeFunction> + ProgramStatePair assumeDualImpl(ProgramStateRef &State, + AssumeFunction &Assume); }; std::unique_ptr<ConstraintManager>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits