@@ -4354,6 +4354,20 @@ static bool isBreakScope(const Token* const endToken)
43544354 return Token::findmatch (endToken->link (), " break|goto" , endToken);
43554355}
43564356
4357+ // If this is the body of a loop, the loop always exits through an unconditional break:
4358+ // the last statement is a top-level break and no continue (or goto) can jump back to
4359+ // evaluate the loop condition again
4360+ static bool isUnconditionalBreakScope (const Token* const endToken)
4361+ {
4362+ if (!Token::simpleMatch (endToken, " }" ))
4363+ return false ;
4364+ if (!Token::simpleMatch (endToken->link (), " {" ))
4365+ return false ;
4366+ if (!Token::Match (endToken->tokAt (-2 ), " break ;" ) || !Token::Match (endToken->tokAt (-3 ), " {|}|;" ))
4367+ return false ;
4368+ return !Token::findmatch (endToken->link (), " continue|goto" , endToken);
4369+ }
4370+
43574371ValueFlow::Value ValueFlow::asImpossible (ValueFlow::Value v)
43584372{
43594373 v.invertRange ();
@@ -4901,10 +4915,12 @@ struct ConditionHandler {
49014915 Token* after = top->link ()->linkAt (1 );
49024916 bool dead_if = deadBranch[0 ];
49034917 bool dead_else = deadBranch[1 ];
4918+ bool alwaysBreaks = false ;
49044919 const Token* unknownFunction = nullptr ;
4905- if (condTok->astParent () && Token::Match (top->previous (), " while|for (" ))
4920+ if (condTok->astParent () && Token::Match (top->previous (), " while|for (" )) {
49064921 dead_if = !isBreakScope (after);
4907- else if (!dead_if)
4922+ alwaysBreaks = isUnconditionalBreakScope (after);
4923+ } else if (!dead_if)
49084924 dead_if = isReturnScope (after, settings.library , &unknownFunction);
49094925
49104926 // If the taken branch might not return (it ends in a call to an unknown,
@@ -4943,12 +4959,15 @@ struct ConditionHandler {
49434959 [](const ValueFlow::Value& v) {
49444960 return v.isPossible () || v.isInconclusive ();
49454961 });
4946- std::copy_if (elseValues.cbegin (),
4947- elseValues.cend (),
4948- std::back_inserter (values),
4949- [](const ValueFlow::Value& v) {
4950- return v.isPossible () || v.isInconclusive ();
4951- });
4962+ // if the loop body always breaks then the loop condition is evaluated at most once,
4963+ // so the false-condition values from iterating the loop do not apply after the loop
4964+ if (!alwaysBreaks)
4965+ std::copy_if (elseValues.cbegin (),
4966+ elseValues.cend (),
4967+ std::back_inserter (values),
4968+ [](const ValueFlow::Value& v) {
4969+ return v.isPossible () || v.isInconclusive ();
4970+ });
49524971 }
49534972
49544973 if (values.empty ())
@@ -5453,8 +5472,11 @@ static void valueFlowForLoop(const TokenList &tokenlist, const SymbolDatabase& s
54535472 valueFlowForward (bodyStart, bodyStart->link (), vartok, std::move (lastValues), tokenlist, errorLogger, settings);
54545473 }
54555474 }
5456- const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
5457- valueFlowForLoopSimplifyAfter (tok, varid, afterValue, tokenlist, errorLogger, settings);
5475+ // if the body always exits through a break the counter does not reach its final value
5476+ if (!executeBody || !isUnconditionalBreakScope (bodyStart->link ())) {
5477+ const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
5478+ valueFlowForLoopSimplifyAfter (tok, varid, afterValue, tokenlist, errorLogger, settings);
5479+ }
54585480 } else {
54595481 ProgramMemory mem1, mem2, memAfter;
54605482 if (valueFlowForLoop2 (tok, mem1, mem2, memAfter, settings)) {
@@ -5485,14 +5507,17 @@ static void valueFlowForLoop(const TokenList &tokenlist, const SymbolDatabase& s
54855507 valueFlowForLoopSimplify (bodyStart, p.first .tok , false , p.second .intvalue , tokenlist, errorLogger, settings);
54865508 }
54875509 }
5488- for (const auto & p : memAfter) {
5489- if (!p.second .isIntValue ())
5490- continue ;
5491- if (p.second .isImpossible ())
5492- continue ;
5493- if (p.first .tok ->varId () == 0 )
5494- continue ;
5495- valueFlowForLoopSimplifyAfter (tok, p.first .getExpressionId (), p.second .intvalue , tokenlist, errorLogger, settings);
5510+ // if the body always exits through a break the counters do not reach their final values
5511+ if (!isUnconditionalBreakScope (bodyStart->link ())) {
5512+ for (const auto & p : memAfter) {
5513+ if (!p.second .isIntValue ())
5514+ continue ;
5515+ if (p.second .isImpossible ())
5516+ continue ;
5517+ if (p.first .tok ->varId () == 0 )
5518+ continue ;
5519+ valueFlowForLoopSimplifyAfter (tok, p.first .getExpressionId (), p.second .intvalue , tokenlist, errorLogger, settings);
5520+ }
54965521 }
54975522 }
54985523 }
0 commit comments