Skip to content

Commit 15a4f63

Browse files
Fix #14247 FN returnDanglingLifetime with designated initializer (#7937)
Co-authored-by: chrchr-github <[email protected]>
1 parent 61a9b2e commit 15a4f63

File tree

4 files changed

+56
-4
lines changed

4 files changed

+56
-4
lines changed

lib/astutils.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,11 @@ const Token* isInLoopCondition(const Token* tok)
10221022
return Token::Match(top->previous(), "for|while (") ? top : nullptr;
10231023
}
10241024

1025+
bool isDesignatedInitializer(const Token* tok)
1026+
{
1027+
return tok && tok->isUnaryOp(".");
1028+
}
1029+
10251030
/// If tok2 comes after tok1
10261031
bool precedes(const Token * tok1, const Token * tok2)
10271032
{

lib/astutils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,11 @@ bool isStructuredBindingVariable(const Variable* var);
265265

266266
const Token* isInLoopCondition(const Token* tok);
267267

268+
/**
269+
* Is token the dot of a designated initializer?
270+
*/
271+
bool isDesignatedInitializer(const Token* tok);
272+
268273
/**
269274
* Is token used as boolean, that is to say cast to a bool, or used as a condition in a if/while/for
270275
*/

lib/valueflow.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,6 +2860,7 @@ static void valueFlowLifetimeClassConstructor(Token* tok,
28602860
std::vector<const Token*> args = getArguments(tok);
28612861
if (scope->numConstructors == 0) {
28622862
auto it = scope->varlist.cbegin();
2863+
const bool hasDesignatedInitializers = !args.empty() && isDesignatedInitializer(args[0]->astOperand1());
28632864
LifetimeStore::forEach(
28642865
tokenlist,
28652866
errorLogger,
@@ -2869,20 +2870,25 @@ static void valueFlowLifetimeClassConstructor(Token* tok,
28692870
ValueFlow::Value::LifetimeKind::SubObject,
28702871
[&](LifetimeStore& ls) {
28712872
// Skip static variable
2872-
it = std::find_if(it, scope->varlist.cend(), [](const Variable& var) {
2873-
return !var.isStatic();
2873+
it = std::find_if(it, scope->varlist.cend(), [&](const Variable &var) {
2874+
return !var.isStatic() && (!hasDesignatedInitializers || var.name() == ls.argtok->astOperand1()->astOperand1()->str());
28742875
});
28752876
if (it == scope->varlist.cend())
28762877
return;
2877-
const Variable& var = *it;
2878+
if (hasDesignatedInitializers)
2879+
ls.argtok = ls.argtok->astOperand2();
2880+
const Variable &var = *it;
28782881
if (var.valueType() && var.valueType()->container && var.valueType()->container->stdStringLike && !var.valueType()->container->view)
28792882
return; // TODO: check in isLifetimeBorrowed()?
28802883
if (var.isReference() || var.isRValueReference()) {
28812884
ls.byRef(tok, tokenlist, errorLogger, settings);
28822885
} else if (ValueFlow::isLifetimeBorrowed(ls.argtok, settings)) {
28832886
ls.byVal(tok, tokenlist, errorLogger, settings);
28842887
}
2885-
it++;
2888+
if (hasDesignatedInitializers)
2889+
it = scope->varlist.cbegin();
2890+
else
2891+
it++;
28862892
});
28872893
} else {
28882894
const Function* constructor = findConstructor(scope, tok, args);

test/testautovariables.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3937,6 +3937,42 @@ class TestAutoVariables : public TestFixture {
39373937
ASSERT_EQUALS(
39383938
"[test.cpp:6:30] -> [test.cpp:6:30] -> [test.cpp:6:21] -> [test.cpp:5:21] -> [test.cpp:8:12]: (error) Returning object that points to local variable 'a' that will be invalid when returning. [returnDanglingLifetime]\n",
39393939
errout_str());
3940+
3941+
check("struct A { int& x; };\n" // #14247
3942+
"A f() {\n"
3943+
" int x = 0;\n"
3944+
" A a{.x = x};\n"
3945+
" return a;\n"
3946+
"}\n");
3947+
ASSERT_EQUALS(
3948+
"[test.cpp:4:14] -> [test.cpp:3:9] -> [test.cpp:5:12]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n",
3949+
errout_str());
3950+
3951+
check("struct A { int x; int& r};\n"
3952+
"A f(int& r) {\n"
3953+
" int x = 0;\n"
3954+
" A a{.x = x, .r = r};\n"
3955+
" return a;\n"
3956+
"}\n");
3957+
ASSERT_EQUALS("", errout_str());
3958+
3959+
check("struct A { int& x; };\n"
3960+
"A f() {\n"
3961+
" int x = 0;\n"
3962+
" A a{ .x{x} };\n"
3963+
" return a;\n"
3964+
"}\n");
3965+
ASSERT_EQUALS(
3966+
"[test.cpp:4:13] -> [test.cpp:3:9] -> [test.cpp:5:12]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n",
3967+
errout_str());
3968+
3969+
check("struct A { int x; int& r};\n"
3970+
"A f(int& r) {\n"
3971+
" int x = 0;\n"
3972+
" A a{ .x{x}, .r{r} };\n"
3973+
" return a;\n"
3974+
"}\n");
3975+
ASSERT_EQUALS("", errout_str());
39403976
}
39413977

39423978
void danglingLifetimeInitList() {

0 commit comments

Comments
 (0)