Fix issue 9930: valueFlowLifetime hang
This commit is contained in:
parent
c373be0b16
commit
828a5e2326
|
@ -3387,18 +3387,54 @@ struct LifetimeStore {
|
||||||
ValueFlow::Value::LifetimeKind type;
|
ValueFlow::Value::LifetimeKind type;
|
||||||
ErrorPath errorPath;
|
ErrorPath errorPath;
|
||||||
bool inconclusive;
|
bool inconclusive;
|
||||||
|
bool forward;
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
Token* tok;
|
||||||
|
TokenList* tokenlist;
|
||||||
|
ErrorLogger* errorLogger;
|
||||||
|
const Settings* settings;
|
||||||
|
};
|
||||||
|
|
||||||
LifetimeStore()
|
LifetimeStore()
|
||||||
: argtok(nullptr), message(), type(), errorPath(), inconclusive(false)
|
: argtok(nullptr), message(), type(), errorPath(), inconclusive(false), forward(true), mContext(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
LifetimeStore(const Token *argtok,
|
LifetimeStore(const Token* argtok,
|
||||||
const std::string &message,
|
const std::string& message,
|
||||||
ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object,
|
ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object,
|
||||||
bool inconclusive = false)
|
bool inconclusive = false)
|
||||||
: argtok(argtok), message(message), type(type), errorPath(), inconclusive(inconclusive)
|
: argtok(argtok),
|
||||||
|
message(message),
|
||||||
|
type(type),
|
||||||
|
errorPath(),
|
||||||
|
inconclusive(inconclusive),
|
||||||
|
forward(true),
|
||||||
|
mContext(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
static void forEach(const std::vector<const Token*>& argtoks,
|
||||||
|
const std::string& message,
|
||||||
|
ValueFlow::Value::LifetimeKind type,
|
||||||
|
F f)
|
||||||
|
{
|
||||||
|
std::map<const Token*, Context> forwardToks;
|
||||||
|
for (const Token* arg : argtoks) {
|
||||||
|
LifetimeStore ls{arg, message, type};
|
||||||
|
Context c{};
|
||||||
|
ls.mContext = &c;
|
||||||
|
ls.forward = false;
|
||||||
|
f(ls);
|
||||||
|
if (c.tok)
|
||||||
|
forwardToks[c.tok] = c;
|
||||||
|
}
|
||||||
|
for (const auto& p : forwardToks) {
|
||||||
|
const Context& c = p.second;
|
||||||
|
valueFlowForwardLifetime(c.tok, c.tokenlist, c.errorLogger, c.settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static LifetimeStore fromFunctionArg(const Function * f, Token *tok, const Variable *var, TokenList *tokenlist, ErrorLogger *errorLogger) {
|
static LifetimeStore fromFunctionArg(const Function * f, Token *tok, const Variable *var, TokenList *tokenlist, ErrorLogger *errorLogger) {
|
||||||
if (!var)
|
if (!var)
|
||||||
return LifetimeStore{};
|
return LifetimeStore{};
|
||||||
|
@ -3423,18 +3459,20 @@ struct LifetimeStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Predicate>
|
template <class Predicate>
|
||||||
void byRef(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings, Predicate pred) const {
|
bool byRef(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings, Predicate pred) const
|
||||||
|
{
|
||||||
if (!argtok)
|
if (!argtok)
|
||||||
return;
|
return false;
|
||||||
|
bool update = false;
|
||||||
for (const LifetimeToken& lt : getLifetimeTokens(argtok)) {
|
for (const LifetimeToken& lt : getLifetimeTokens(argtok)) {
|
||||||
if (!settings->inconclusive && lt.inconclusive)
|
if (!settings->inconclusive && lt.inconclusive)
|
||||||
continue;
|
continue;
|
||||||
ErrorPath er = errorPath;
|
ErrorPath er = errorPath;
|
||||||
er.insert(er.end(), lt.errorPath.begin(), lt.errorPath.end());
|
er.insert(er.end(), lt.errorPath.begin(), lt.errorPath.end());
|
||||||
if (!lt.token)
|
if (!lt.token)
|
||||||
return;
|
return false;
|
||||||
if (!pred(lt.token))
|
if (!pred(lt.token))
|
||||||
return;
|
return false;
|
||||||
er.emplace_back(argtok, message);
|
er.emplace_back(argtok, message);
|
||||||
|
|
||||||
ValueFlow::Value value;
|
ValueFlow::Value value;
|
||||||
|
@ -3446,22 +3484,26 @@ struct LifetimeStore {
|
||||||
value.setInconclusive(lt.inconclusive || inconclusive);
|
value.setInconclusive(lt.inconclusive || inconclusive);
|
||||||
// Don't add the value a second time
|
// Don't add the value a second time
|
||||||
if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
|
if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
|
||||||
return;
|
return false;
|
||||||
setTokenValue(tok, value, tokenlist->getSettings());
|
setTokenValue(tok, value, tokenlist->getSettings());
|
||||||
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
update = true;
|
||||||
}
|
}
|
||||||
|
if (update && forward)
|
||||||
|
forwardLifetime(tok, tokenlist, errorLogger, settings);
|
||||||
|
return update;
|
||||||
}
|
}
|
||||||
|
|
||||||
void byRef(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) const {
|
bool byRef(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const
|
||||||
byRef(tok, tokenlist, errorLogger, settings, [](const Token *) {
|
{
|
||||||
return true;
|
return byRef(tok, tokenlist, errorLogger, settings, [](const Token*) { return true; });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Predicate>
|
template <class Predicate>
|
||||||
void byVal(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings, Predicate pred) const {
|
bool byVal(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings, Predicate pred) const
|
||||||
|
{
|
||||||
if (!argtok)
|
if (!argtok)
|
||||||
return;
|
return false;
|
||||||
|
bool update = false;
|
||||||
if (argtok->values().empty()) {
|
if (argtok->values().empty()) {
|
||||||
ErrorPath er;
|
ErrorPath er;
|
||||||
er.emplace_back(argtok, message);
|
er.emplace_back(argtok, message);
|
||||||
|
@ -3476,9 +3518,9 @@ struct LifetimeStore {
|
||||||
value.setInconclusive(inconclusive);
|
value.setInconclusive(inconclusive);
|
||||||
// Don't add the value a second time
|
// Don't add the value a second time
|
||||||
if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
|
if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
|
||||||
return;
|
return false;
|
||||||
setTokenValue(tok, value, tokenlist->getSettings());
|
setTokenValue(tok, value, tokenlist->getSettings());
|
||||||
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
update = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const ValueFlow::Value &v : argtok->values()) {
|
for (const ValueFlow::Value &v : argtok->values()) {
|
||||||
|
@ -3491,9 +3533,9 @@ struct LifetimeStore {
|
||||||
ErrorPath er = v.errorPath;
|
ErrorPath er = v.errorPath;
|
||||||
er.insert(er.end(), lt.errorPath.begin(), lt.errorPath.end());
|
er.insert(er.end(), lt.errorPath.begin(), lt.errorPath.end());
|
||||||
if (!lt.token)
|
if (!lt.token)
|
||||||
return;
|
return false;
|
||||||
if (!pred(lt.token))
|
if (!pred(lt.token))
|
||||||
return;
|
return false;
|
||||||
er.emplace_back(argtok, message);
|
er.emplace_back(argtok, message);
|
||||||
er.insert(er.end(), errorPath.begin(), errorPath.end());
|
er.insert(er.end(), errorPath.begin(), errorPath.end());
|
||||||
|
|
||||||
|
@ -3509,15 +3551,17 @@ struct LifetimeStore {
|
||||||
if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
|
if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
|
||||||
continue;
|
continue;
|
||||||
setTokenValue(tok, value, tokenlist->getSettings());
|
setTokenValue(tok, value, tokenlist->getSettings());
|
||||||
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
update = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (update && forward)
|
||||||
|
forwardLifetime(tok, tokenlist, errorLogger, settings);
|
||||||
|
return update;
|
||||||
}
|
}
|
||||||
|
|
||||||
void byVal(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) const {
|
bool byVal(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const
|
||||||
byVal(tok, tokenlist, errorLogger, settings, [](const Token *) {
|
{
|
||||||
return true;
|
return byVal(tok, tokenlist, errorLogger, settings, [](const Token*) { return true; });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Predicate>
|
template <class Predicate>
|
||||||
|
@ -3549,6 +3593,19 @@ struct LifetimeStore {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Context* mContext;
|
||||||
|
void forwardLifetime(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const
|
||||||
|
{
|
||||||
|
if (mContext) {
|
||||||
|
mContext->tok = tok;
|
||||||
|
mContext->tokenlist = tokenlist;
|
||||||
|
mContext->errorLogger = errorLogger;
|
||||||
|
mContext->settings = settings;
|
||||||
|
}
|
||||||
|
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
|
@ -3603,6 +3660,7 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
|
||||||
return;
|
return;
|
||||||
std::vector<const Token*> returns = Function::findReturns(f);
|
std::vector<const Token*> returns = Function::findReturns(f);
|
||||||
const bool inconclusive = returns.size() > 1;
|
const bool inconclusive = returns.size() > 1;
|
||||||
|
bool update = false;
|
||||||
for (const Token* returnTok : returns) {
|
for (const Token* returnTok : returns) {
|
||||||
if (returnTok == tok)
|
if (returnTok == tok)
|
||||||
continue;
|
continue;
|
||||||
|
@ -3610,7 +3668,8 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
|
||||||
if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings, tokenlist->isCPP()))) {
|
if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings, tokenlist->isCPP()))) {
|
||||||
LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, errorLogger);
|
LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, errorLogger);
|
||||||
ls.inconclusive = inconclusive;
|
ls.inconclusive = inconclusive;
|
||||||
ls.byVal(tok->next(), tokenlist, errorLogger, settings);
|
ls.forward = false;
|
||||||
|
update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
|
||||||
}
|
}
|
||||||
for (const ValueFlow::Value &v : returnTok->values()) {
|
for (const ValueFlow::Value &v : returnTok->values()) {
|
||||||
if (!v.isLifetimeValue())
|
if (!v.isLifetimeValue())
|
||||||
|
@ -3621,16 +3680,19 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
|
||||||
LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, var, tokenlist, errorLogger);
|
LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, var, tokenlist, errorLogger);
|
||||||
if (!ls.argtok)
|
if (!ls.argtok)
|
||||||
continue;
|
continue;
|
||||||
|
ls.forward = false;
|
||||||
ls.inconclusive = inconclusive;
|
ls.inconclusive = inconclusive;
|
||||||
ls.errorPath = v.errorPath;
|
ls.errorPath = v.errorPath;
|
||||||
ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + ".");
|
ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + ".");
|
||||||
if (!v.isArgumentLifetimeValue() && (var->isReference() || var->isRValueReference())) {
|
if (!v.isArgumentLifetimeValue() && (var->isReference() || var->isRValueReference())) {
|
||||||
ls.byRef(tok->next(), tokenlist, errorLogger, settings);
|
update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings);
|
||||||
} else if (v.isArgumentLifetimeValue()) {
|
} else if (v.isArgumentLifetimeValue()) {
|
||||||
ls.byVal(tok->next(), tokenlist, errorLogger, settings);
|
update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (update)
|
||||||
|
valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3648,11 +3710,11 @@ static void valueFlowLifetimeConstructor(Token* tok,
|
||||||
// If the type is unknown then assume it captures by value in the
|
// If the type is unknown then assume it captures by value in the
|
||||||
// constructor, but make each lifetime inconclusive
|
// constructor, but make each lifetime inconclusive
|
||||||
std::vector<const Token*> args = getArguments(tok);
|
std::vector<const Token*> args = getArguments(tok);
|
||||||
for (const Token *argtok : args) {
|
LifetimeStore::forEach(
|
||||||
LifetimeStore ls{argtok, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::Object};
|
args, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::Object, [&](LifetimeStore& ls) {
|
||||||
ls.inconclusive = true;
|
ls.inconclusive = true;
|
||||||
ls.byVal(tok, tokenlist, errorLogger, settings);
|
ls.byVal(tok, tokenlist, errorLogger, settings);
|
||||||
}
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Scope* scope = t->classScope;
|
const Scope* scope = t->classScope;
|
||||||
|
@ -3661,20 +3723,21 @@ static void valueFlowLifetimeConstructor(Token* tok,
|
||||||
// Only support aggregate constructors for now
|
// Only support aggregate constructors for now
|
||||||
if (scope->numConstructors == 0 && t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) {
|
if (scope->numConstructors == 0 && t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) {
|
||||||
std::vector<const Token*> args = getArguments(tok);
|
std::vector<const Token*> args = getArguments(tok);
|
||||||
std::size_t i = 0;
|
auto it = scope->varlist.begin();
|
||||||
for (const Variable& var : scope->varlist) {
|
LifetimeStore::forEach(args,
|
||||||
if (i >= args.size())
|
"Passed to constructor of '" + t->name() + "'.",
|
||||||
break;
|
ValueFlow::Value::LifetimeKind::Object,
|
||||||
const Token* argtok = args[i];
|
[&](const LifetimeStore& ls) {
|
||||||
LifetimeStore ls{
|
if (it == scope->varlist.end())
|
||||||
argtok, "Passed to constructor of '" + t->name() + "'.", ValueFlow::Value::LifetimeKind::Object};
|
return;
|
||||||
if (var.isReference() || var.isRValueReference()) {
|
const Variable& var = *it;
|
||||||
ls.byRef(tok, tokenlist, errorLogger, settings);
|
if (var.isReference() || var.isRValueReference()) {
|
||||||
} else {
|
ls.byRef(tok, tokenlist, errorLogger, settings);
|
||||||
ls.byVal(tok, tokenlist, errorLogger, settings);
|
} else {
|
||||||
}
|
ls.byVal(tok, tokenlist, errorLogger, settings);
|
||||||
i++;
|
}
|
||||||
}
|
it++;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3704,15 +3767,15 @@ static void valueFlowLifetimeConstructor(Token* tok, TokenList* tokenlist, Error
|
||||||
std::vector<const Token *> args = getArguments(tok);
|
std::vector<const Token *> args = getArguments(tok);
|
||||||
// Assume range constructor if passed a pair of iterators
|
// Assume range constructor if passed a pair of iterators
|
||||||
if (astIsContainer(parent) && args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1])) {
|
if (astIsContainer(parent) && args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1])) {
|
||||||
for (const Token *argtok : args) {
|
LifetimeStore::forEach(
|
||||||
LifetimeStore ls{argtok, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::Object};
|
args, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::Object, [&](const LifetimeStore& ls) {
|
||||||
ls.byDerefCopy(tok, tokenlist, errorLogger, settings);
|
ls.byDerefCopy(tok, tokenlist, errorLogger, settings);
|
||||||
}
|
});
|
||||||
} else {
|
} else {
|
||||||
for (const Token *argtok : args) {
|
LifetimeStore::forEach(args,
|
||||||
LifetimeStore ls{argtok, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::Object};
|
"Passed to initializer list.",
|
||||||
ls.byVal(tok, tokenlist, errorLogger, settings);
|
ValueFlow::Value::LifetimeKind::Object,
|
||||||
}
|
[&](const LifetimeStore& ls) { ls.byVal(tok, tokenlist, errorLogger, settings); });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
valueFlowLifetimeConstructor(tok, Token::typeOf(tok->previous()), tokenlist, errorLogger, settings);
|
valueFlowLifetimeConstructor(tok, Token::typeOf(tok->previous()), tokenlist, errorLogger, settings);
|
||||||
|
@ -3822,16 +3885,21 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool update = false;
|
||||||
auto captureVariable = [&](const Token* tok2, Lambda::Capture c, std::function<bool(const Token*)> pred) {
|
auto captureVariable = [&](const Token* tok2, Lambda::Capture c, std::function<bool(const Token*)> pred) {
|
||||||
if (varids.count(tok->varId()) > 0)
|
if (varids.count(tok->varId()) > 0)
|
||||||
return;
|
return;
|
||||||
ErrorPath errorPath;
|
ErrorPath errorPath;
|
||||||
if (c == Lambda::Capture::ByReference) {
|
if (c == Lambda::Capture::ByReference) {
|
||||||
LifetimeStore{tok2, "Lambda captures variable by reference here.", ValueFlow::Value::LifetimeKind::Lambda} .byRef(
|
LifetimeStore ls{
|
||||||
tok, tokenlist, errorLogger, settings, pred);
|
tok2, "Lambda captures variable by reference here.", ValueFlow::Value::LifetimeKind::Lambda};
|
||||||
|
ls.forward = false;
|
||||||
|
update |= ls.byRef(tok, tokenlist, errorLogger, settings, pred);
|
||||||
} else if (c == Lambda::Capture::ByValue) {
|
} else if (c == Lambda::Capture::ByValue) {
|
||||||
LifetimeStore{tok2, "Lambda captures variable by value here.", ValueFlow::Value::LifetimeKind::Lambda} .byVal(
|
LifetimeStore ls{
|
||||||
tok, tokenlist, errorLogger, settings, pred);
|
tok2, "Lambda captures variable by value here.", ValueFlow::Value::LifetimeKind::Lambda};
|
||||||
|
ls.forward = false;
|
||||||
|
update |= ls.byVal(tok, tokenlist, errorLogger, settings, pred);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3853,8 +3921,8 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
|
||||||
continue;
|
continue;
|
||||||
captureVariable(tok2, lam.implicitCapture, isImplicitCapturingVariable);
|
captureVariable(tok2, lam.implicitCapture, isImplicitCapturingVariable);
|
||||||
}
|
}
|
||||||
|
if (update)
|
||||||
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
||||||
}
|
}
|
||||||
// address of
|
// address of
|
||||||
else if (tok->isUnaryOp("&")) {
|
else if (tok->isUnaryOp("&")) {
|
||||||
|
|
|
@ -4897,6 +4897,36 @@ private:
|
||||||
" ) {}\n"
|
" ) {}\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
valueOfTok(code, "x");
|
valueOfTok(code, "x");
|
||||||
|
|
||||||
|
code = "namespace {\n"
|
||||||
|
"struct a {\n"
|
||||||
|
" a(...) {}\n"
|
||||||
|
" a(std::initializer_list<std::pair<int, std::vector<std::vector<a>>>>) {}\n"
|
||||||
|
"} b{{0, {{&b, &b, &b, &b}}},\n"
|
||||||
|
" {0,\n"
|
||||||
|
" {{&b, &b, &b, &b, &b, &b, &b, &b, &b, &b},\n"
|
||||||
|
" {{&b, &b, &b, &b, &b, &b, &b}}}},\n"
|
||||||
|
" {0,\n"
|
||||||
|
" {{&b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b},\n"
|
||||||
|
" {&b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b}}}};\n"
|
||||||
|
"}\n";
|
||||||
|
valueOfTok(code, "x");
|
||||||
|
|
||||||
|
code = "namespace {\n"
|
||||||
|
"struct a {\n"
|
||||||
|
" a(...) {}\n"
|
||||||
|
" a(std::initializer_list<std::pair<int, std::vector<std::vector<a>>>>) {}\n"
|
||||||
|
"} b{{0, {{&b}}},\n"
|
||||||
|
" {0, {{&b}}},\n"
|
||||||
|
" {0, {{&b}}},\n"
|
||||||
|
" {0, {{&b}}},\n"
|
||||||
|
" {0, {{&b}, {&b, &b, &b, &b, &b, &b, &b, &b, &b, &b, {&b}}}},\n"
|
||||||
|
" {0,\n"
|
||||||
|
" {{&b},\n"
|
||||||
|
" {&b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b, &b,\n"
|
||||||
|
" &b}}}};\n"
|
||||||
|
"}\n";
|
||||||
|
valueOfTok(code, "x");
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowCrashConstructorInitialization() { // #9577
|
void valueFlowCrashConstructorInitialization() { // #9577
|
||||||
|
|
Loading…
Reference in New Issue