@@ -3387,18 +3387,54 @@ struct LifetimeStore {
33873387 ValueFlow::Value::LifetimeKind type;
33883388 ErrorPath errorPath;
33893389 bool inconclusive;
3390+ bool forward;
3391+
3392+ struct Context {
3393+ Token* tok;
3394+ TokenList* tokenlist;
3395+ ErrorLogger* errorLogger;
3396+ const Settings* settings;
3397+ };
33903398
33913399 LifetimeStore ()
3392- : argtok(nullptr ), message(), type(), errorPath(), inconclusive(false )
3400+ : argtok(nullptr ), message(), type(), errorPath(), inconclusive(false ), forward( true ), mContext ( nullptr )
33933401 {}
33943402
3395- LifetimeStore (const Token * argtok,
3396- const std::string & message,
3403+ LifetimeStore (const Token* argtok,
3404+ const std::string& message,
33973405 ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object,
33983406 bool inconclusive = false )
3399- : argtok(argtok), message(message), type(type), errorPath(), inconclusive(inconclusive)
3407+ : argtok(argtok),
3408+ message (message),
3409+ type(type),
3410+ errorPath(),
3411+ inconclusive(inconclusive),
3412+ forward(true ),
3413+ mContext(nullptr )
34003414 {}
34013415
3416+ template <class F >
3417+ static void forEach (const std::vector<const Token*>& argtoks,
3418+ const std::string& message,
3419+ ValueFlow::Value::LifetimeKind type,
3420+ F f)
3421+ {
3422+ std::map<const Token*, Context> forwardToks;
3423+ for (const Token* arg : argtoks) {
3424+ LifetimeStore ls{arg, message, type};
3425+ Context c{};
3426+ ls.mContext = &c;
3427+ ls.forward = false ;
3428+ f (ls);
3429+ if (c.tok )
3430+ forwardToks[c.tok ] = c;
3431+ }
3432+ for (const auto & p : forwardToks) {
3433+ const Context& c = p.second ;
3434+ valueFlowForwardLifetime (c.tok , c.tokenlist , c.errorLogger , c.settings );
3435+ }
3436+ }
3437+
34023438 static LifetimeStore fromFunctionArg (const Function * f, Token *tok, const Variable *var, TokenList *tokenlist, ErrorLogger *errorLogger) {
34033439 if (!var)
34043440 return LifetimeStore{};
@@ -3423,18 +3459,20 @@ struct LifetimeStore {
34233459 }
34243460
34253461 template <class Predicate >
3426- void byRef (Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings, Predicate pred) const {
3462+ bool byRef (Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings, Predicate pred) const
3463+ {
34273464 if (!argtok)
3428- return ;
3465+ return false ;
3466+ bool update = false ;
34293467 for (const LifetimeToken& lt : getLifetimeTokens (argtok)) {
34303468 if (!settings->inconclusive && lt.inconclusive )
34313469 continue ;
34323470 ErrorPath er = errorPath;
34333471 er.insert (er.end (), lt.errorPath .begin (), lt.errorPath .end ());
34343472 if (!lt.token )
3435- return ;
3473+ return false ;
34363474 if (!pred (lt.token ))
3437- return ;
3475+ return false ;
34383476 er.emplace_back (argtok, message);
34393477
34403478 ValueFlow::Value value;
@@ -3446,22 +3484,26 @@ struct LifetimeStore {
34463484 value.setInconclusive (lt.inconclusive || inconclusive);
34473485 // Don't add the value a second time
34483486 if (std::find (tok->values ().begin (), tok->values ().end (), value) != tok->values ().end ())
3449- return ;
3487+ return false ;
34503488 setTokenValue (tok, value, tokenlist->getSettings ());
3451- valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings) ;
3489+ update = true ;
34523490 }
3491+ if (update && forward)
3492+ forwardLifetime (tok, tokenlist, errorLogger, settings);
3493+ return update;
34533494 }
34543495
3455- void byRef (Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) const {
3456- byRef (tok, tokenlist, errorLogger, settings, [](const Token *) {
3457- return true ;
3458- });
3496+ bool byRef (Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const
3497+ {
3498+ return byRef (tok, tokenlist, errorLogger, settings, [](const Token*) { return true ; });
34593499 }
34603500
34613501 template <class Predicate >
3462- void byVal (Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings, Predicate pred) const {
3502+ bool byVal (Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings, Predicate pred) const
3503+ {
34633504 if (!argtok)
3464- return ;
3505+ return false ;
3506+ bool update = false ;
34653507 if (argtok->values ().empty ()) {
34663508 ErrorPath er;
34673509 er.emplace_back (argtok, message);
@@ -3476,9 +3518,9 @@ struct LifetimeStore {
34763518 value.setInconclusive (inconclusive);
34773519 // Don't add the value a second time
34783520 if (std::find (tok->values ().begin (), tok->values ().end (), value) != tok->values ().end ())
3479- return ;
3521+ return false ;
34803522 setTokenValue (tok, value, tokenlist->getSettings ());
3481- valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings) ;
3523+ update = true ;
34823524 }
34833525 }
34843526 for (const ValueFlow::Value &v : argtok->values ()) {
@@ -3491,9 +3533,9 @@ struct LifetimeStore {
34913533 ErrorPath er = v.errorPath ;
34923534 er.insert (er.end (), lt.errorPath .begin (), lt.errorPath .end ());
34933535 if (!lt.token )
3494- return ;
3536+ return false ;
34953537 if (!pred (lt.token ))
3496- return ;
3538+ return false ;
34973539 er.emplace_back (argtok, message);
34983540 er.insert (er.end (), errorPath.begin (), errorPath.end ());
34993541
@@ -3509,15 +3551,17 @@ struct LifetimeStore {
35093551 if (std::find (tok->values ().begin (), tok->values ().end (), value) != tok->values ().end ())
35103552 continue ;
35113553 setTokenValue (tok, value, tokenlist->getSettings ());
3512- valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings) ;
3554+ update = true ;
35133555 }
35143556 }
3557+ if (update && forward)
3558+ forwardLifetime (tok, tokenlist, errorLogger, settings);
3559+ return update;
35153560 }
35163561
3517- void byVal (Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) const {
3518- byVal (tok, tokenlist, errorLogger, settings, [](const Token *) {
3519- return true ;
3520- });
3562+ bool byVal (Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const
3563+ {
3564+ return byVal (tok, tokenlist, errorLogger, settings, [](const Token*) { return true ; });
35213565 }
35223566
35233567 template <class Predicate >
@@ -3549,6 +3593,19 @@ struct LifetimeStore {
35493593 return true ;
35503594 });
35513595 }
3596+
3597+ private:
3598+ Context* mContext ;
3599+ void forwardLifetime (Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const
3600+ {
3601+ if (mContext ) {
3602+ mContext ->tok = tok;
3603+ mContext ->tokenlist = tokenlist;
3604+ mContext ->errorLogger = errorLogger;
3605+ mContext ->settings = settings;
3606+ }
3607+ valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings);
3608+ }
35523609};
35533610
35543611static void valueFlowLifetimeFunction (Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
@@ -3603,14 +3660,16 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
36033660 return ;
36043661 std::vector<const Token*> returns = Function::findReturns (f);
36053662 const bool inconclusive = returns.size () > 1 ;
3663+ bool update = false ;
36063664 for (const Token* returnTok : returns) {
36073665 if (returnTok == tok)
36083666 continue ;
36093667 const Variable *returnVar = getLifetimeVariable (returnTok);
36103668 if (returnVar && returnVar->isArgument () && (returnVar->isConst () || !isVariableChanged (returnVar, settings, tokenlist->isCPP ()))) {
36113669 LifetimeStore ls = LifetimeStore::fromFunctionArg (f, tok, returnVar, tokenlist, errorLogger);
36123670 ls.inconclusive = inconclusive;
3613- ls.byVal (tok->next (), tokenlist, errorLogger, settings);
3671+ ls.forward = false ;
3672+ update |= ls.byVal (tok->next (), tokenlist, errorLogger, settings);
36143673 }
36153674 for (const ValueFlow::Value &v : returnTok->values ()) {
36163675 if (!v.isLifetimeValue ())
@@ -3621,16 +3680,19 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
36213680 LifetimeStore ls = LifetimeStore::fromFunctionArg (f, tok, var, tokenlist, errorLogger);
36223681 if (!ls.argtok )
36233682 continue ;
3683+ ls.forward = false ;
36243684 ls.inconclusive = inconclusive;
36253685 ls.errorPath = v.errorPath ;
36263686 ls.errorPath .emplace_front (returnTok, " Return " + lifetimeType (returnTok, &v) + " ." );
36273687 if (!v.isArgumentLifetimeValue () && (var->isReference () || var->isRValueReference ())) {
3628- ls.byRef (tok->next (), tokenlist, errorLogger, settings);
3688+ update |= ls.byRef (tok->next (), tokenlist, errorLogger, settings);
36293689 } else if (v.isArgumentLifetimeValue ()) {
3630- ls.byVal (tok->next (), tokenlist, errorLogger, settings);
3690+ update |= ls.byVal (tok->next (), tokenlist, errorLogger, settings);
36313691 }
36323692 }
36333693 }
3694+ if (update)
3695+ valueFlowForwardLifetime (tok->next (), tokenlist, errorLogger, settings);
36343696 }
36353697}
36363698
@@ -3648,11 +3710,11 @@ static void valueFlowLifetimeConstructor(Token* tok,
36483710 // If the type is unknown then assume it captures by value in the
36493711 // constructor, but make each lifetime inconclusive
36503712 std::vector<const Token*> args = getArguments (tok);
3651- for ( const Token *argtok : args) {
3652- LifetimeStore ls{argtok , " Passed to initializer list." , ValueFlow::Value::LifetimeKind::Object};
3653- ls.inconclusive = true ;
3654- ls.byVal (tok, tokenlist, errorLogger, settings);
3655- }
3713+ LifetimeStore::forEach (
3714+ args , " Passed to initializer list." , ValueFlow::Value::LifetimeKind::Object, [&](LifetimeStore& ls) {
3715+ ls.inconclusive = true ;
3716+ ls.byVal (tok, tokenlist, errorLogger, settings);
3717+ });
36563718 return ;
36573719 }
36583720 const Scope* scope = t->classScope ;
@@ -3661,20 +3723,21 @@ static void valueFlowLifetimeConstructor(Token* tok,
36613723 // Only support aggregate constructors for now
36623724 if (scope->numConstructors == 0 && t->derivedFrom .empty () && (t->isClassType () || t->isStructType ())) {
36633725 std::vector<const Token*> args = getArguments (tok);
3664- std::size_t i = 0 ;
3665- for (const Variable& var : scope->varlist ) {
3666- if (i >= args.size ())
3667- break ;
3668- const Token* argtok = args[i];
3669- LifetimeStore ls{
3670- argtok, " Passed to constructor of '" + t->name () + " '." , ValueFlow::Value::LifetimeKind::Object};
3671- if (var.isReference () || var.isRValueReference ()) {
3672- ls.byRef (tok, tokenlist, errorLogger, settings);
3673- } else {
3674- ls.byVal (tok, tokenlist, errorLogger, settings);
3675- }
3676- i++;
3677- }
3726+ auto it = scope->varlist .begin ();
3727+ LifetimeStore::forEach (args,
3728+ " Passed to constructor of '" + t->name () + " '." ,
3729+ ValueFlow::Value::LifetimeKind::Object,
3730+ [&](const LifetimeStore& ls) {
3731+ if (it == scope->varlist .end ())
3732+ return ;
3733+ const Variable& var = *it;
3734+ if (var.isReference () || var.isRValueReference ()) {
3735+ ls.byRef (tok, tokenlist, errorLogger, settings);
3736+ } else {
3737+ ls.byVal (tok, tokenlist, errorLogger, settings);
3738+ }
3739+ it++;
3740+ });
36783741 }
36793742}
36803743
@@ -3704,15 +3767,15 @@ static void valueFlowLifetimeConstructor(Token* tok, TokenList* tokenlist, Error
37043767 std::vector<const Token *> args = getArguments (tok);
37053768 // Assume range constructor if passed a pair of iterators
37063769 if (astIsContainer (parent) && args.size () == 2 && astIsIterator (args[0 ]) && astIsIterator (args[1 ])) {
3707- for ( const Token *argtok : args) {
3708- LifetimeStore ls{argtok , " Passed to initializer list." , ValueFlow::Value::LifetimeKind::Object};
3709- ls.byDerefCopy (tok, tokenlist, errorLogger, settings);
3710- }
3770+ LifetimeStore::forEach (
3771+ args , " Passed to initializer list." , ValueFlow::Value::LifetimeKind::Object, [&]( const LifetimeStore& ls) {
3772+ ls.byDerefCopy (tok, tokenlist, errorLogger, settings);
3773+ });
37113774 } else {
3712- for ( const Token *argtok : args) {
3713- LifetimeStore ls{argtok, " Passed to initializer list." , ValueFlow::Value::LifetimeKind::Object};
3714- ls. byVal (tok, tokenlist, errorLogger, settings);
3715- }
3775+ LifetimeStore::forEach ( args,
3776+ " Passed to initializer list." ,
3777+ ValueFlow::Value::LifetimeKind::Object,
3778+ [&]( const LifetimeStore& ls) { ls. byVal (tok, tokenlist, errorLogger, settings); });
37163779 }
37173780 } else {
37183781 valueFlowLifetimeConstructor (tok, Token::typeOf (tok->previous ()), tokenlist, errorLogger, settings);
@@ -3822,16 +3885,21 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
38223885 return true ;
38233886 };
38243887
3888+ bool update = false ;
38253889 auto captureVariable = [&](const Token* tok2, Lambda::Capture c, std::function<bool (const Token*)> pred) {
38263890 if (varids.count (tok->varId ()) > 0 )
38273891 return ;
38283892 ErrorPath errorPath;
38293893 if (c == Lambda::Capture::ByReference) {
3830- LifetimeStore{tok2, " Lambda captures variable by reference here." , ValueFlow::Value::LifetimeKind::Lambda} .byRef (
3831- tok, tokenlist, errorLogger, settings, pred);
3894+ LifetimeStore ls{
3895+ tok2, " Lambda captures variable by reference here." , ValueFlow::Value::LifetimeKind::Lambda};
3896+ ls.forward = false ;
3897+ update |= ls.byRef (tok, tokenlist, errorLogger, settings, pred);
38323898 } else if (c == Lambda::Capture::ByValue) {
3833- LifetimeStore{tok2, " Lambda captures variable by value here." , ValueFlow::Value::LifetimeKind::Lambda} .byVal (
3834- tok, tokenlist, errorLogger, settings, pred);
3899+ LifetimeStore ls{
3900+ tok2, " Lambda captures variable by value here." , ValueFlow::Value::LifetimeKind::Lambda};
3901+ ls.forward = false ;
3902+ update |= ls.byVal (tok, tokenlist, errorLogger, settings, pred);
38353903 }
38363904 };
38373905
@@ -3853,8 +3921,8 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
38533921 continue ;
38543922 captureVariable (tok2, lam.implicitCapture , isImplicitCapturingVariable);
38553923 }
3856-
3857- valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings);
3924+ if (update)
3925+ valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings);
38583926 }
38593927 // address of
38603928 else if (tok->isUnaryOp (" &" )) {
0 commit comments