From 2978c67e6f791d3ff553f6dcc332ca023dfe9f97 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Thu, 5 Dec 2019 21:19:46 -0600 Subject: [PATCH] Fix issue 9511: Syntax Error: AST broken, 'if' doesn't have two operands. (#2428) --- lib/tokenlist.cpp | 13 +++++++++-- test/testtokenize.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index a9ba65c52..4bd270c16 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -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) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 4987a9d20..9e60849bc 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -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"