Skip to content

Commit 440310e

Browse files
autoantwortclaude
andcommitted
Keep the reference of the return type in the ValueType of a function pointer
The type of a call through a function pointer is derived from the ValueType of the pointer, so resetting the reference caused false positives like returnTempReference for `int& f(int& (*fp)()) { return fp(); }`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent da724f2 commit 440310e

3 files changed

Lines changed: 23 additions & 9 deletions

File tree

‎lib/symboldatabase.cpp‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7582,8 +7582,6 @@ static const Token* parsedecl(const Token* type,
75827582
if (par)
75837583
break;
75847584
par = true;
7585-
// a reference before the parentheses belongs to the return type of the function pointer
7586-
valuetype->reference = Reference::None;
75877585
}
75887586
if (Token::simpleMatch(type, "decltype (") && type->next()->valueType()) {
75897587
const ValueType *vt2 = type->next()->valueType();

‎test/testautovariables.cpp‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class TestAutoVariables : public TestFixture {
133133
TEST_CASE(returnReference27);
134134
TEST_CASE(returnReference28);
135135
TEST_CASE(returnReference29);
136+
TEST_CASE(returnReference30); // #15094
136137
TEST_CASE(returnReferenceFunction);
137138
TEST_CASE(returnReferenceContainer);
138139
TEST_CASE(returnReferenceLiteral);
@@ -1772,6 +1773,23 @@ class TestAutoVariables : public TestFixture {
17721773
errout_str());
17731774
}
17741775

1776+
void returnReference30() // #15094
1777+
{
1778+
check("int& f1(int& (*fp)()) { return fp(); }\n"
1779+
"void f2(int& (*fp)()) { int& r = fp(); r = 2; }\n"
1780+
"struct D {\n"
1781+
" int& call() { return f(); }\n"
1782+
" int& (*f)();\n"
1783+
"};\n"
1784+
"const int& f3(const int& (*fp)(int)) { return fp(1); }\n"
1785+
"int& (*g)();\n"
1786+
"int& f4() { return g(); }\n"
1787+
"typedef int& (*FP)();\n"
1788+
"int& f5(FP fp) { return fp(); }\n"
1789+
"int* f6(int& (*fp)()) { return &fp(); }\n");
1790+
ASSERT_EQUALS("", errout_str());
1791+
}
1792+
17751793
void returnReferenceFunction() {
17761794
check("int& f(int& a) {\n"
17771795
" return a;\n"

‎test/testsymboldatabase.cpp‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,30 +1602,28 @@ class TestSymbolDatabase : public TestFixture {
16021602
ASSERT(p->valueType()->originalTypeName == "ubFunctionPointer_fp");
16031603
ASSERT(p->valueType()->reference == Reference::None);
16041604
}
1605-
{ // function pointer returning a reference
1605+
{ // function pointer returning a reference, the ValueType keeps the reference of the return type
16061606
GET_SYMBOL_DB("void foo(int& (*f)()) {}\n");
16071607
const Variable* const p = db->getVariableFromVarId(1);
16081608
ASSERT(!p->isReference());
16091609
ASSERT(p->isPointer());
16101610
ASSERT(p->valueType());
16111611
ASSERT(p->valueType()->pointer == 1);
1612-
ASSERT(p->valueType()->reference == Reference::None);
1612+
ASSERT(p->valueType()->reference == Reference::LValue);
16131613
}
16141614
{
16151615
GET_SYMBOL_DB("void foo(int&& (*f)()) {}\n");
16161616
const Variable* const p = db->getVariableFromVarId(1);
16171617
ASSERT(!p->isReference());
16181618
ASSERT(!p->isRValueReference());
16191619
ASSERT(p->valueType());
1620-
ASSERT(p->valueType()->reference == Reference::None);
1620+
ASSERT(p->valueType()->reference == Reference::RValue);
16211621
}
16221622
{
16231623
GET_SYMBOL_DB("struct S { int& (*f[2])(); };\n");
16241624
const Variable* const p = db->getVariableFromVarId(1);
16251625
ASSERT(!p->isReference());
16261626
ASSERT(p->isArray());
1627-
ASSERT(p->valueType());
1628-
ASSERT(p->valueType()->reference == Reference::None);
16291627
}
16301628
{ // pointer to member function returning a reference
16311629
GET_SYMBOL_DB("struct S { int& g(); };\n"
@@ -1634,8 +1632,6 @@ class TestSymbolDatabase : public TestFixture {
16341632
ASSERT(p);
16351633
ASSERT_EQUALS("pm", p->name());
16361634
ASSERT(!p->isReference());
1637-
ASSERT(p->valueType());
1638-
ASSERT(p->valueType()->reference == Reference::None);
16391635
}
16401636
{ // parentheses that are no function declarator
16411637
GET_SYMBOL_DB("void foo(int& (r)) {}\n");
@@ -9910,6 +9906,8 @@ class TestSymbolDatabase : public TestFixture {
99109906
ASSERT_EQUALS("signed long", typeOf("a = (long)32;\n", "("));
99119907
ASSERT_EQUALS("signed long", typeOf("a = (long int)32;\n", "("));
99129908
ASSERT_EQUALS("signed long long", typeOf("a = (long long)32;\n", "("));
9909+
ASSERT_EQUALS("signed int &", typeOf("void f(int& (*fp)()) { fp(); }\n", "( ) ;")); // #15094
9910+
ASSERT_EQUALS("signed int &&", typeOf("void f(int&& (*fp)()) { fp(); }\n", "( ) ;"));
99139911
ASSERT_EQUALS("long double", typeOf("a = (long double)32;\n", "("));
99149912
ASSERT_EQUALS("char", typeOf("a = static_cast<char>(32);\n", "("));
99159913
ASSERT_EQUALS("", typeOf("a = (unsigned x)0;\n", "("));

0 commit comments

Comments
 (0)