diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9f2ae419ed4..2e438cdb8dc 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8642,7 +8642,8 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator") syntaxError(tok, tok->str() + " " + tok->strAt(1)); - if (Token::simpleMatch(tok, "::") && (!Token::Match(tok->next(), "%name%|*|~") || (tok->next()->isKeyword() && tok->strAt(1) != "operator"))) + if (Token::simpleMatch(tok, "::") && (!Token::Match(tok->next(), "%name%|*|~") || + (tok->next()->isKeyword() && !Token::Match(tok->next(), "new|delete|operator")))) syntaxError(tok); if (Token::Match(tok, "& %comp%|&&|%oror%|&|%or%") && tok->strAt(1) != ">") syntaxError(tok); diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 87567f1f162..d5122ab6a9d 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -749,7 +749,7 @@ static void compileTerm(Token *&tok, AST_state& state) tok = tok->next(); } while (Token::Match(tok, "%name%|%str%")); } else if (tok->isName()) { - if (Token::Match(tok, "return|case") || (state.cpp && (tok->str() == "throw" || Token::simpleMatch(tok->tokAt(-1), ":: new")))) { + if (Token::Match(tok, "return|case") || (state.cpp && (tok->str() == "throw"))) { if (tok->str() == "case") state.inCase = true; const bool tokIsReturn = tok->str() == "return"; @@ -1160,6 +1160,10 @@ static void compilePrecedence3(Token *&tok, AST_state& state) compilePrecedence2(tok, state); } compileUnaryOp(newtok, state, nullptr); + if (Token::simpleMatch(newtok->previous(), ":: new")) { + newtok->previous()->astOperand1(newtok); + state.op.pop(); + } if (innertype && Token::simpleMatch(tok, ") ,")) tok = tok->next(); } else if (state.cpp && Token::Match(tok, "delete %name%|*|&|::|(|[")) { @@ -1169,6 +1173,10 @@ static void compilePrecedence3(Token *&tok, AST_state& state) tok = tok->link()->next(); compilePrecedence3(tok, state); compileUnaryOp(tok2, state, nullptr); + if (Token::simpleMatch(tok2->previous(), ":: delete")) { + tok2->previous()->astOperand1(tok2); + state.op.pop(); + } } // TODO: Handle sizeof else break; diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index d08cc6a69ff..f90fbb45d7a 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6251,6 +6251,8 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("pint5[{new=", testAst("p = new int* [5]{};")); ASSERT_EQUALS("pint5[0{new=", testAst("p = new int* [5]{ 0 };")); ASSERT_EQUALS("sSint(new::(new=", testAst("s = new S(::new int());")); // #12502 + ASSERT_EQUALS("sS(new::=", testAst("s = ::new (ptr) S();")); // #12552 + ASSERT_EQUALS("pdelete::return", testAst("return ::delete p;")); // placement new ASSERT_EQUALS("X12,3,(new ab,c,", testAst("new (a,b,c) X(1,2,3);")); @@ -7083,6 +7085,9 @@ class TestTokenizer : public TestFixture { "There is an unknown macro here somewhere. Configuration is required. If MACRO is a macro then please configure it."); ASSERT_THROW(tokenizeAndStringify("{ for (()()) }"), InternalError); // #11643 + + ASSERT_NO_THROW(tokenizeAndStringify("S* g = ::new(ptr) S();")); // #12552 + ASSERT_NO_THROW(tokenizeAndStringify("void f(int* p) { return ::delete p; }")); }