Fix issue 9511: Syntax Error: AST broken, 'if' doesn't have two operands. (#2428)

This commit is contained in:
Paul Fultz II 2019-12-05 21:19:46 -06:00 committed by Daniel Marjamäki
parent 5979eec2c0
commit 2978c67e6f
2 changed files with 65 additions and 2 deletions

View File

@ -601,6 +601,15 @@ static bool iscpp11init_impl(const Token * const tok)
return true;
}
static bool isRefQualifier(const Token* tok)
{
if (!Token::Match(tok, "&|&&"))
return false;
if (!Token::Match(tok->next(), "{|;"))
return false;
return true;
}
static void compileUnaryOp(Token *&tok, AST_state& state, void(*f)(Token *&tok, AST_state& state))
{
Token *unaryop = tok;
@ -1027,7 +1036,7 @@ static void compileAnd(Token *&tok, AST_state& state)
{
compileEqComp(tok, state);
while (tok) {
if (tok->str() == "&" && !tok->astOperand1()) {
if (tok->str() == "&" && !tok->astOperand1() && !isRefQualifier(tok)) {
Token* tok2 = tok->next();
if (!tok2)
break;
@ -1066,7 +1075,7 @@ static void compileLogicAnd(Token *&tok, AST_state& state)
{
compileOr(tok, state);
while (tok) {
if (tok->str() == "&&") {
if (tok->str() == "&&" && !isRefQualifier(tok)) {
if (!tok->astOperand1()) {
Token* tok2 = tok->next();
if (!tok2)

View File

@ -456,6 +456,7 @@ private:
TEST_CASE(astcast);
TEST_CASE(astlambda);
TEST_CASE(astcase);
TEST_CASE(astrefqualifier);
TEST_CASE(astvardecl);
TEST_CASE(startOfExecutableScope);
@ -472,6 +473,7 @@ private:
TEST_CASE(checkNamespaces);
TEST_CASE(checkLambdas);
TEST_CASE(checkIfCppCast);
TEST_CASE(checkRefQualifiers);
// #9052
TEST_CASE(noCrash1);
@ -7820,6 +7822,15 @@ private:
ASSERT_EQUALS("xyz:?case", testAst("case (x?y:z):"));
}
void astrefqualifier() {
ASSERT_EQUALS("b(int.", testAst("class a { auto b() -> int&; };"));
ASSERT_EQUALS("b(int.", testAst("class a { auto b() -> int&&; };"));
ASSERT_EQUALS("b(", testAst("class a { void b() &&; };"));
ASSERT_EQUALS("b(", testAst("class a { void b() &; };"));
ASSERT_EQUALS("b(", testAst("class a { void b() && {} };"));
ASSERT_EQUALS("b(", testAst("class a { void b() & {} };"));
}
void compileLimits() {
const char raw_code[] = "#define PTR1 (* (* (* (* (* (* (* (* (* (*\n"
"#define PTR2 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1\n"
@ -8095,6 +8106,49 @@ private:
"}\n"))
}
// #9511
void checkRefQualifiers() {
ASSERT_NO_THROW(tokenizeAndStringify("class a {\n"
" void b() && {\n"
" if (this) {}\n"
" }\n"
"};\n"))
ASSERT_NO_THROW(tokenizeAndStringify("class a {\n"
" void b() & {\n"
" if (this) {}\n"
" }\n"
"};\n"))
ASSERT_NO_THROW(tokenizeAndStringify("class a {\n"
" auto b() && -> void {\n"
" if (this) {}\n"
" }\n"
"};\n"))
ASSERT_NO_THROW(tokenizeAndStringify("class a {\n"
" auto b() & -> void {\n"
" if (this) {}\n"
" }\n"
"};\n"))
ASSERT_NO_THROW(tokenizeAndStringify("class a {\n"
" auto b(int& x) -> int& {\n"
" if (this) {}\n"
" return x;\n"
" }\n"
"};\n"))
ASSERT_NO_THROW(tokenizeAndStringify("class a {\n"
" auto b(int& x) -> int&& {\n"
" if (this) {}\n"
" return x;\n"
" }\n"
"};\n"))
ASSERT_NO_THROW(tokenizeAndStringify("class a {\n"
" auto b(int& x) && -> int& {\n"
" if (this) {}\n"
" return x;\n"
" }\n"
"};\n"))
}
void noCrash1() {
ASSERT_NO_THROW(tokenizeAndStringify(
"struct A {\n"