diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 394a0e42add..c4923f8ccee 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9177,9 +9177,11 @@ void Tokenizer::findGarbageCode() const if (!Token::Match(tok->next(), "%name%|*|~") || (tok->next()->isKeyword() && !Token::Match(tok->next(), "new|delete|operator"))) syntaxError(tok); if (Token::simpleMatch(tok->tokAt(-1), ")")) { + // NAME(...):: => NAME is most likely an unknown macro + // other cases are valid, e.g. (void)::f(), return (T)::x, new (p) ::T, decltype(x)::type const Token* const prev = tok->linkAt(-1)->tokAt(-1); - if (!Token::Match(prev, "%name% (") || (!prev->isControlFlowKeyword() && prev->str() != "decltype")) { - if (prev && prev->isUpperCaseName()) + if (Token::Match(prev, "%name% (") && !prev->isKeyword()) { + if (prev->isUpperCaseName()) unknownMacroError(prev); else syntaxError(tok); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index fca4b9db613..e0d63f404e3 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8135,6 +8135,22 @@ class TestTokenizer : public TestFixture { " *p = -*p;\n" "}\n")); + ASSERT_NO_THROW(tokenizeAndStringify("void f(void* h) {\n" // cast before global scope operator + " (void)::CloseHandle(h);\n" + " int i = (int)::GetTickCount();\n" + " g((unsigned char)::toupper(i));\n" + "}\n")); + ASSERT_NO_THROW(tokenizeAndStringify("int f(int i) {\n" + " return (int)::abs(i);\n" + "}\n")); + ASSERT_NO_THROW(tokenizeAndStringify("namespace N { struct T {}; }\n" + "void f(void* p) {\n" + " new (p) ::N::T;\n" + "}\n")); + ASSERT_NO_THROW(tokenizeAndStringify("struct S { using type = int; };\n" + "S s;\n" + "decltype(s)::type i;\n")); + ignore_errout(); ASSERT_EQUALS(";", tokenizeAndStringify("typedef std::size_t size_t;\n")); // #14809