fix #8965 ("(debug) Executable scope 'x' with unknown function." with rvalue parameter in method) (#2237)

I fixed the AST enough to pass testrunner but I don't believe it is
correct.

This code:

void Foo4(int&&b);

has this AST:

( 'void'
|-Foo4
`-&& 'bool'
  |-int
  `-b 'signed int'

but I don't believe && should have `bool`.
This commit is contained in:
IOBYTE 2019-10-04 06:30:11 -04:00 committed by Daniel Marjamäki
parent 2a33c3cfec
commit c32a568c1f
9 changed files with 28 additions and 42 deletions

View File

@ -2318,18 +2318,6 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration)
createSymbolDatabase(); createSymbolDatabase();
} }
// Use symbol database to identify rvalue references. Split && to & &. This is safe, since it doesn't delete any tokens (which might be referenced by symbol database)
for (const Variable* var : mSymbolDatabase->variableList()) {
if (var && var->isRValueReference()) {
Token* endTok = const_cast<Token*>(var->typeEndToken());
endTok->str("&");
endTok->astOperand1(nullptr);
endTok->astOperand2(nullptr);
endTok->insertToken("&");
endTok->next()->scope(endTok->scope());
}
}
if (mTimerResults) { if (mTimerResults) {
Timer t("Tokenizer::simplifyTokens1::setValueType", mSettings->showtime, mTimerResults); Timer t("Tokenizer::simplifyTokens1::setValueType", mSettings->showtime, mTimerResults);
mSymbolDatabase->setValueTypeInTokenList(true); mSymbolDatabase->setValueTypeInTokenList(true);
@ -4636,8 +4624,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
elseif(); elseif();
SimplifyNamelessRValueReferences();
validate(); validate();
list.front()->assignIndexes(); list.front()->assignIndexes();
@ -11240,17 +11226,6 @@ void Tokenizer::setPodTypes()
} }
} }
void Tokenizer::SimplifyNamelessRValueReferences()
{
// Simplify nameless rValue references - named ones are simplified later
for (Token* tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "&& [,)]")) {
tok->str("&");
tok->insertToken("&");
}
}
}
const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart) const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart)
{ {
const Token *tokLastEnd = nullptr; const Token *tokLastEnd = nullptr;

View File

@ -154,8 +154,6 @@ public:
*/ */
bool simplifyTokenList1(const char FileName[]); bool simplifyTokenList1(const char FileName[]);
void SimplifyNamelessRValueReferences();
/** /**
* Most aggressive simplification of tokenlist * Most aggressive simplification of tokenlist
* *

View File

@ -1034,6 +1034,15 @@ static void compileLogicAnd(Token *&tok, AST_state& state)
compileOr(tok, state); compileOr(tok, state);
while (tok) { while (tok) {
if (tok->str() == "&&") { if (tok->str() == "&&") {
if (!tok->astOperand1()) {
Token* tok2 = tok->next();
if (!tok2)
break;
if (state.cpp && Token::Match(tok2, ",|)")) {
tok = tok2;
break; // rValue reference
}
}
compileBinOp(tok, state, compileOr); compileBinOp(tok, state, compileOr);
} else break; } else break;
} }

View File

@ -445,13 +445,13 @@ private:
check("void f() {\n" check("void f() {\n"
" const Token *tok;\n" " const Token *tok;\n"
" if(a && b && && c && tok && Token::Match(tok, \"5str% foobar\")) {};\n" " if(a && b && c && tok && Token::Match(tok, \"5str% foobar\")) {};\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (style) Unnecessary check of \"tok\", match-function already checks if it is null.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (style) Unnecessary check of \"tok\", match-function already checks if it is null.\n", errout.str());
check("void f() {\n" check("void f() {\n"
" const Token *tok;\n" " const Token *tok;\n"
" if(a && b && && c && tok && d && Token::Match(tok, \"5str% foobar\")) {};\n" " if(a && b && c && tok && d && Token::Match(tok, \"5str% foobar\")) {};\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());

View File

@ -3000,19 +3000,19 @@ private:
"a<int> c ; " "a<int> c ; "
"template < typename d > " "template < typename d > "
"template < typename b > " "template < typename b > "
"const decltype ( auto ) a < d > :: operator() ( b & & ) const { } " "const decltype ( auto ) a < d > :: operator() ( b && ) const { } "
"struct a<int> { " "struct a<int> { "
"template < typename b > const decltype ( auto ) operator() ( b & & ) const ; " "template < typename b > const decltype ( auto ) operator() ( b && ) const ; "
"} ;"; "} ;";
const char act[] = "struct a<int> ; " const char act[] = "struct a<int> ; "
"a<int> c ; " "a<int> c ; "
"template < typename d > " "template < typename d > "
"template < typename b > " "template < typename b > "
"const decltype ( auto ) a < d > :: operator() ( b & & ) const { } " "const decltype ( auto ) a < d > :: operator() ( b && ) const { } "
"struct a<int> { " "struct a<int> { "
"template < typename b > const decltype ( auto ) operator() ( b & & ) const ; " "template < typename b > const decltype ( auto ) operator() ( b && ) const ; "
"} ; " "} ; "
"const decltype ( auto ) a<int> :: operator() ( b & & ) const { }"; "const decltype ( auto ) a<int> :: operator() ( b && ) const { }";
TODO_ASSERT_EQUALS(exp, act, tok(code)); TODO_ASSERT_EQUALS(exp, act, tok(code));
} }
{ {

View File

@ -2221,8 +2221,8 @@ private:
void simplifyTypedef109() { void simplifyTypedef109() {
const char code[] = "typedef int&& rref;\n" const char code[] = "typedef int&& rref;\n"
"rref var;"; "rref var = 0;";
const char expected[] = "int & & var ;"; const char expected[] = "int && var ; var = 0 ;";
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }

View File

@ -1559,7 +1559,7 @@ private:
ASSERT(ctor && ctor->retDef == nullptr); ASSERT(ctor && ctor->retDef == nullptr);
} }
{ {
GET_SYMBOL_DB("class Foo { Foo(Foo & & f, int default = 1, bool defaultToo = true); };"); GET_SYMBOL_DB("class Foo { Foo(Foo&& f, int default = 1, bool defaultToo = true); };");
const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); const Function* ctor = tokenizer.tokens()->tokAt(3)->function();
ASSERT(db && ctor && ctor->type == Function::eMoveConstructor); ASSERT(db && ctor && ctor->type == Function::eMoveConstructor);
ASSERT(ctor && ctor->retDef == nullptr); ASSERT(ctor && ctor->retDef == nullptr);

View File

@ -7269,7 +7269,11 @@ private:
ASSERT_EQUALS("catch...(", testAst("try {} catch (...) {}")); ASSERT_EQUALS("catch...(", testAst("try {} catch (...) {}"));
ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar&);")); ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar&);"));
ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar& &);")); // Rvalue reference - simplified from && to & & by real tokenizer ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar&&);"));
ASSERT_EQUALS("FooBarb&(", testAst("void Foo(Bar& b);"));
ASSERT_EQUALS("FooBarb&&(", testAst("void Foo(Bar&& b);"));
ASSERT_EQUALS("DerivedDerived::(", testAst("Derived::~Derived() {}")); ASSERT_EQUALS("DerivedDerived::(", testAst("Derived::~Derived() {}"));
ASSERT_EQUALS("ifCA_FarReadfilenew(,sizeofobjtype(,(!(", testAst("if (!CA_FarRead(file, (void far *)new, sizeof(objtype)))")); // #5910 - don't hang if C code is parsed as C++ ASSERT_EQUALS("ifCA_FarReadfilenew(,sizeofobjtype(,(!(", testAst("if (!CA_FarRead(file, (void far *)new, sizeof(objtype)))")); // #5910 - don't hang if C code is parsed as C++

View File

@ -2222,18 +2222,18 @@ private:
} }
void varid_rvalueref() { void varid_rvalueref() {
ASSERT_EQUALS("1: int & & a@1 ;\n", tokenize("int&& a;")); ASSERT_EQUALS("1: int && a@1 ;\n", tokenize("int&& a;"));
ASSERT_EQUALS("1: void foo ( int & & a@1 ) { }\n", tokenize("void foo(int&& a) {}")); ASSERT_EQUALS("1: void foo ( int && a@1 ) { }\n", tokenize("void foo(int&& a) {}"));
ASSERT_EQUALS("1: class C {\n" ASSERT_EQUALS("1: class C {\n"
"2: C ( int & & a@1 ) ;\n" "2: C ( int && a@1 ) ;\n"
"3: } ;\n", "3: } ;\n",
tokenize("class C {\n" tokenize("class C {\n"
" C(int&& a);\n" " C(int&& a);\n"
"};")); "};"));
ASSERT_EQUALS("1: void foo ( int & & ) ;\n", tokenize("void foo(int&&);")); ASSERT_EQUALS("1: void foo ( int && ) ;\n", tokenize("void foo(int&&);"));
} }
void varid_arrayFuncPar() { void varid_arrayFuncPar() {