From 46578c52caf5c71e83b26a4f4523bd24470784ef Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 26 Sep 2022 20:20:22 +0200 Subject: [PATCH 1/9] Fix internalAstError with new --- lib/tokenlist.cpp | 34 ++++++++++++++++++++++++++-------- test/testtokenize.cpp | 5 ++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 33f867d7d78..1fc81a60ba2 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -912,8 +912,20 @@ static bool isPrefixUnary(const Token* tok, bool cpp) static void compilePrecedence2(Token *&tok, AST_state& state) { - const bool isStartOfCpp11Init = state.cpp && tok && tok->str() == "{" && iscpp11init(tok); - if (!(isStartOfCpp11Init && Token::Match(tok->tokAt(-2), "new %type% {"))) + auto doCompileScope = [&](const Token* tok) -> bool { + const bool isStartOfCpp11Init = state.cpp && tok && tok->str() == "{" && iscpp11init(tok); + if (isStartOfCpp11Init) { + tok = tok->previous(); + while (Token::Match(tok->previous(), ":: %type%")) + tok = tok->tokAt(-2); + if (tok && !tok->isKeyword()) + tok = tok->previous(); + return !Token::Match(tok, "new ::| %type%"); + } + return true; + }; + + if (doCompileScope(tok)) compileScope(tok, state); while (tok) { if (tok->tokType() == Token::eIncDecOp && !isPrefixUnary(tok, state.cpp)) { @@ -1069,12 +1081,18 @@ static void compilePrecedence3(Token *&tok, AST_state& state) } Token* leftToken = tok; - while (Token::Match(tok->next(), ":: %name%")) { - Token* scopeToken = tok->next(); //The :: - scopeToken->astOperand1(leftToken); - scopeToken->astOperand2(scopeToken->next()); - leftToken = scopeToken; - tok = scopeToken->next(); + if (Token::simpleMatch(tok, "::")) { + tok->astOperand1(tok->next()); + tok = tok->next(); + } + else { + while (Token::Match(tok->next(), ":: %name%")) { + Token* scopeToken = tok->next(); //The :: + scopeToken->astOperand1(leftToken); + scopeToken->astOperand2(scopeToken->next()); + leftToken = scopeToken; + tok = scopeToken->next(); + } } state.op.push(tok); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index bc86eec3f33..fee6f894ddd 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6071,10 +6071,13 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("Aa*A12,{new=", testAst("A* a = new A{ 1, 2 };")); ASSERT_EQUALS("Sv0[(new", testAst("new S(v[0]);")); // #10929 ASSERT_EQUALS("SS::x(px0>intx[{newint1[{new:?(:", testAst("S::S(int x) : p(x > 0 ? new int[x]{} : new int[1]{}) {}")); // #10793 + ASSERT_EQUALS("a0[T{new=", testAst("a[0] = new T{};")); + ASSERT_EQUALS("a0[T::{new=", testAst("a[0] = new ::T{};")); + ASSERT_EQUALS("a0[ST::{new=", testAst("a[0] = new S::T{};")); // placement new ASSERT_EQUALS("X12,3,(new ab,c,", testAst("new (a,b,c) X(1,2,3);")); - ASSERT_EQUALS("a::new=", testAst("a = new (b) ::X;")); + ASSERT_EQUALS("aX::new=", testAst("a = new (b) ::X;")); ASSERT_EQUALS("cCnew= abc:?", testAst("c = new(a ? b : c) C;")); // invalid code (libreoffice), don't hang From f981c1011db2326104a123e1e5c8c705eeb4bef3 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 26 Sep 2022 20:22:43 +0200 Subject: [PATCH 2/9] Format --- lib/tokenlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 1fc81a60ba2..139e04d0990 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -924,7 +924,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state) } return true; }; - + if (doCompileScope(tok)) compileScope(tok, state); while (tok) { From ac7503d95228901a5e1a007e8abc003edbc51158 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 26 Sep 2022 21:24:17 +0200 Subject: [PATCH 3/9] nullptr check --- lib/tokenlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 139e04d0990..e95f5219671 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -916,7 +916,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state) const bool isStartOfCpp11Init = state.cpp && tok && tok->str() == "{" && iscpp11init(tok); if (isStartOfCpp11Init) { tok = tok->previous(); - while (Token::Match(tok->previous(), ":: %type%")) + while (tok && Token::Match(tok->previous(), ":: %type%")) tok = tok->tokAt(-2); if (tok && !tok->isKeyword()) tok = tok->previous(); From a8c7db6e47f6a1cc8da95bcb7c3fdfb07e1034c2 Mon Sep 17 00:00:00 2001 From: chrchr Date: Tue, 27 Sep 2022 16:07:34 +0200 Subject: [PATCH 4/9] Add test for #11039 --- test/testtokenize.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index fee6f894ddd..4ac9f5644c6 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6074,6 +6074,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("a0[T{new=", testAst("a[0] = new T{};")); ASSERT_EQUALS("a0[T::{new=", testAst("a[0] = new ::T{};")); ASSERT_EQUALS("a0[ST::{new=", testAst("a[0] = new S::T{};")); + ASSERT_EQUALS("intnewdelete", testAst("delete new int;")); // placement new ASSERT_EQUALS("X12,3,(new ab,c,", testAst("new (a,b,c) X(1,2,3);")); From 93fdcfd2f02d0e1c1466075d0a93e2599f5b79d2 Mon Sep 17 00:00:00 2001 From: chrchr Date: Tue, 27 Sep 2022 17:00:48 +0200 Subject: [PATCH 5/9] Fix #11039 Empty AST with delete new / #11327 FP leakReturnValNotUsed with new and offset --- lib/tokenlist.cpp | 5 ++++- test/testmemleak.cpp | 11 +++++++++++ test/testtokenize.cpp | 4 +++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 139e04d0990..640a00be69b 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -543,6 +543,8 @@ static bool iscast(const Token *tok, bool cpp) for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { if (tok2->varId() != 0) return false; + if (cpp && !type && tok2->str() == "new") + return false; while (tok2->link() && Token::Match(tok2, "(|[|<")) tok2 = tok2->link()->next(); @@ -1620,7 +1622,8 @@ static Token * createAstAtToken(Token *tok, bool cpp) Token::Match(tok, "%name% %op%|(|[|.|::|<|?|;") || (cpp && Token::Match(tok, "%name% {") && iscpp11init(tok->next())) || Token::Match(tok->previous(), "[;{}] %cop%|++|--|( !!{") || - Token::Match(tok->previous(), "[;{}] %num%|%str%|%char%")) { + Token::Match(tok->previous(), "[;{}] %num%|%str%|%char%") || + Token::Match(tok->previous(), "[;{}] delete new")) { if (cpp && (Token::Match(tok->tokAt(-2), "[;{}] new|delete %name%") || Token::Match(tok->tokAt(-3), "[;{}] :: new|delete %name%"))) tok = tok->previous(); diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index a7a6640b3ba..676a77955cf 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -2666,6 +2666,17 @@ class TestMemleakNoVar : public TestFixture { " Ref remove(new StringBuffer());\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" // #11039 + " delete new int;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" // #11327 + " int* p = (new int[3]) + 1;\n" + " delete[] &p[-1];\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void smartPointerFunctionParam() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 4ac9f5644c6..57843ca1959 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6074,7 +6074,9 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("a0[T{new=", testAst("a[0] = new T{};")); ASSERT_EQUALS("a0[T::{new=", testAst("a[0] = new ::T{};")); ASSERT_EQUALS("a0[ST::{new=", testAst("a[0] = new S::T{};")); - ASSERT_EQUALS("intnewdelete", testAst("delete new int;")); + ASSERT_EQUALS("intnewdelete", testAst("delete new int;")); // #11039 + ASSERT_EQUALS("intnewdelete", testAst("void f() { delete new int; }")); + ASSERT_EQUALS("pint3[new1+=", testAst("p = (new int[3]) + 1;")); // #11327 // placement new ASSERT_EQUALS("X12,3,(new ab,c,", testAst("new (a,b,c) X(1,2,3);")); From da9afa0c7ef6d2e4c8ce254e61cd7cc24ef59aa4 Mon Sep 17 00:00:00 2001 From: chrchr Date: Tue, 27 Sep 2022 20:11:18 +0200 Subject: [PATCH 6/9] Fix #10839 internalAstError with function returning a function --- lib/tokenlist.cpp | 4 ++++ test/testtokenize.cpp | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 3db8e0b316f..73ccb7f89eb 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1719,6 +1719,10 @@ void TokenList::validateAst() const tok = tok->link(); continue; } + if (tok->isCast() && tok->astOperand1() && tok->link()) { // skip casts (not part of the AST) + tok = tok->link(); + continue; + } // Check binary operators if (Token::Match(tok, "%or%|%oror%|%assign%|%comp%")) { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 57843ca1959..be6f40c1d26 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6226,6 +6226,26 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("adecltypeac::(,decltypead::(,", testAst("template void b(a &, decltype(a::c), decltype(a::d));")); + ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" // #10839 + "struct B { A* hash; };\n" + "auto g(A* a) { return [=](void*) { return a; }; }\n" + "void f(void* p, B* b) {\n" + " b->hash = (g(b->hash))(p);\n" + "}\n")); + ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" + "struct B { A* hash; };\n" + "A* h(void* p);\n" + "typedef A* (*X)(void*);\n" + "X g(A*) { return h; }\n" + "void f(void* p, B * b) {\n" + "b->hash = (g(b->hash))(p);\n" + "}\n")); + ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" + "struct B { A* hash; };\n" + "void f(void* p, B* b) {\n" + " b->hash = (decltype(b->hash))(p);\n" + "}\n")); + // #10334: Do not hang! tokenizeAndStringify("void foo(const std::vector& locations = {\"\"}) {\n" " for (int i = 0; i <= 123; ++i)\n" From 6326442684da3c8c568201456b689ccfc0ae036f Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 10 Oct 2022 20:58:12 +0200 Subject: [PATCH 7/9] Add test for #10801 --- test/testtokenize.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index be6f40c1d26..d7551bc0381 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6225,6 +6225,14 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("decltypexy+(yx+{", testAst("decltype(x+y){y+x};")); ASSERT_EQUALS("adecltypeac::(,decltypead::(,", testAst("template void b(a &, decltype(a::c), decltype(a::d));")); + + ASSERT_NO_THROW(tokenizeAndStringify("void a(int);\n" // #10801 + " struct b {\n" + " static int c();\n" + "} d;\n" + "void f() {\n" + " (decltype (&a)(d.c))(0);\n" + "}\n")); ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" // #10839 "struct B { A* hash; };\n" From 8f422806dfe441bcc75e03fd7c34058b3ec120ae Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 10 Oct 2022 21:01:01 +0200 Subject: [PATCH 8/9] Format --- test/testtokenize.cpp | 34 +++++++--------------------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 481d3b68cc3..f2412d63608 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6226,14 +6226,6 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("decltypexy+(yx+{", testAst("decltype(x+y){y+x};")); ASSERT_EQUALS("adecltypeac::(,decltypead::(,", testAst("template void b(a &, decltype(a::c), decltype(a::d));")); - - ASSERT_NO_THROW(tokenizeAndStringify("void a(int);\n" // #10801 - " struct b {\n" - " static int c();\n" - "} d;\n" - "void f() {\n" - " (decltype (&a)(d.c))(0);\n" - "}\n")); ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" // #10839 "struct B { A* hash; };\n" @@ -6254,25 +6246,13 @@ class TestTokenizer : public TestFixture { "void f(void* p, B* b) {\n" " b->hash = (decltype(b->hash))(p);\n" "}\n")); - - ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" // #10839 - "struct B { A* hash; };\n" - "auto g(A* a) { return [=](void*) { return a; }; }\n" - "void f(void* p, B* b) {\n" - " b->hash = (g(b->hash))(p);\n" - "}\n")); - ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" - "struct B { A* hash; };\n" - "A* h(void* p);\n" - "typedef A* (*X)(void*);\n" - "X g(A*) { return h; }\n" - "void f(void* p, B * b) {\n" - "b->hash = (g(b->hash))(p);\n" - "}\n")); - ASSERT_NO_THROW(tokenizeAndStringify("struct A;\n" - "struct B { A* hash; };\n" - "void f(void* p, B* b) {\n" - " b->hash = (decltype(b->hash))(p);\n" + + ASSERT_NO_THROW(tokenizeAndStringify("void a(int);\n" // #10801 + " struct b {\n" + " static int c();\n" + "} d;\n" + "void f() {\n" + " (decltype (&a)(d.c))(0);\n" "}\n")); // #10334: Do not hang! From 3a75444dd28f7c965ac72d2a6b71d4651912972b Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:49:11 +0200 Subject: [PATCH 9/9] Update testtokenize.cpp --- test/testtokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index f2412d63608..c733fbf0616 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6246,7 +6246,7 @@ class TestTokenizer : public TestFixture { "void f(void* p, B* b) {\n" " b->hash = (decltype(b->hash))(p);\n" "}\n")); - + ASSERT_NO_THROW(tokenizeAndStringify("void a(int);\n" // #10801 " struct b {\n" " static int c();\n"