@@ -678,16 +678,20 @@ struct ValueFlowAnalyzer : Analyzer {
678678 if (const ValueFlow::Value* v = tok->getKnownValue (ValueFlow::Value::ValueType::INT ))
679679 return {v->intvalue };
680680 std::vector<MathLib::bigint> result;
681- ProgramMemory pm = getProgramMemoryFunc ();
681+ // Pass the tracked values so a cached program-memory value that depends on one (e.g. 'h(p)'
682+ // after 'p' was reassigned) is re-evaluated rather than served stale. The memory is built
683+ // from the same state, so compute it once and hand it to the builder.
684+ const ProgramState vars = getProgramState ();
685+ ProgramMemory pm = getProgramMemoryFunc (vars);
682686 if (Token::Match (tok, " &&|%oror%" )) {
683- if (conditionIsTrue (tok, pm, getSettings ()))
687+ if (conditionIsTrue (tok, pm, getSettings (), vars ))
684688 result.push_back (1 );
685- if (conditionIsFalse (tok, std::move (pm), getSettings ()))
689+ if (conditionIsFalse (tok, std::move (pm), getSettings (), vars ))
686690 result.push_back (0 );
687691 } else {
688692 MathLib::bigint out = 0 ;
689693 bool error = false ;
690- execute (tok, pm, &out, &error, getSettings ());
694+ execute (tok, pm, &out, &error, getSettings (), vars );
691695 if (!error)
692696 result.push_back (out);
693697 }
@@ -696,16 +700,16 @@ struct ValueFlowAnalyzer : Analyzer {
696700
697701 std::vector<MathLib::bigint> evaluateInt (const Token* tok) const
698702 {
699- return evaluateInt (tok, [&] {
700- return ProgramMemory{getProgramState () };
703+ return evaluateInt (tok, []( const ProgramState& vars) {
704+ return ProgramMemory{vars };
701705 });
702706 }
703707
704708 std::vector<MathLib::bigint> evaluate (Evaluate e, const Token* tok, const Token* ctx = nullptr ) const override
705709 {
706710 if (e == Evaluate::Integral) {
707- return evaluateInt (tok, [&] {
708- return pms.get (tok, ctx, getProgramState () );
711+ return evaluateInt (tok, [&]( const ProgramState& vars) {
712+ return pms.get (tok, ctx, vars );
709713 });
710714 }
711715 if (e == Evaluate::ContainerEmpty) {
@@ -723,30 +727,43 @@ struct ValueFlowAnalyzer : Analyzer {
723727 return {};
724728 }
725729
726- void assume (const Token* tok, bool state, unsigned int flags) override {
727- // Update program state
728- pms.removeModifiedVars (tok);
729- pms.addState (tok, getProgramState ());
730- pms.assume (tok, state, flags & Assume::ContainerEmpty);
731-
730+ void assume (const Token* tok, bool state, unsigned int flags) override
731+ {
732732 bool isCondBlock = false ;
733733 const Token* parent = tok->astParent ();
734734 if (parent) {
735735 isCondBlock = Token::Match (parent->previous (), " if|while (" );
736736 }
737737
738+ const Token* endBlock = nullptr ;
738739 if (isCondBlock) {
739740 const Token* startBlock = parent->link ()->next ();
740741 if (Token::simpleMatch (startBlock, " ;" ) && Token::simpleMatch (parent->tokAt (-2 ), " } while (" ))
741742 startBlock = parent->linkAt (-2 );
742- const Token* endBlock = startBlock->link ();
743- if (state) {
744- pms.removeModifiedVars (endBlock);
745- pms.addState (endBlock->previous (), getProgramState ());
746- } else {
747- if (Token::simpleMatch (endBlock, " } else {" ))
748- pms.addState (endBlock->linkAt (2 )->previous (), getProgramState ());
749- }
743+ endBlock = startBlock->link ();
744+ }
745+
746+ // Without Pending the 'then' block has been traversed and control is leaving it, so anchor
747+ // the assumed state at the block end instead of the condition. That keeps assumptions on
748+ // variables modified inside the block (e.g. an 'if' narrowing a value computed there) from
749+ // being discarded as "modified" once control leaves the block.
750+ const bool scopeEnd = !(flags & Assume::Pending) && state && endBlock;
751+ const Token* anchor = scopeEnd ? endBlock : tok;
752+ const Token* origin = scopeEnd ? endBlock : nullptr ;
753+
754+ // Update program state
755+ pms.removeModifiedVars (anchor);
756+ pms.addState (anchor, getProgramState ());
757+ pms.assume (tok, state, flags & Assume::ContainerEmpty, origin);
758+
759+ // The false path (the true path uses scopeEnd above): record the assumed state where control
760+ // continues - the end of the else block, or the closing brace when there is no else - so it
761+ // reaches the enclosing scope.
762+ if (isCondBlock && !(flags & Assume::Pending) && !state) {
763+ if (Token::simpleMatch (endBlock, " } else {" ))
764+ pms.addState (endBlock->linkAt (2 )->previous (), getProgramState ());
765+ else
766+ pms.addState (endBlock, getProgramState ());
750767 }
751768
752769 if (!(flags & Assume::Quiet)) {
0 commit comments