From 29a27cb94ef309b8ee523ad3a3504fde1ffa4c9d Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 15 Jan 2026 21:13:29 +0100 Subject: [PATCH 1/2] Fix #14400 FP syntaxError for trailing return type --- lib/tokenize.cpp | 22 +++++++++++++--------- test/testtokenize.cpp | 6 ++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 96c69bb4dd9..f702947cc95 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -103,14 +103,14 @@ static void skipEnumBody(T *&tok) /** * is tok the start brace { of a class, struct, union, or enum */ -static bool isClassStructUnionEnumStart(const Token * tok) +static const Token* isClassStructUnionEnumStart(const Token * tok) { if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {")) - return false; + return nullptr; const Token * tok2 = tok->previous(); while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|)|;|>|>>")) tok2 = tok2->previous(); - return Token::Match(tok2, "class|struct|union|enum"); + return Token::Match(tok2, "class|struct|union|enum") ? tok2 : nullptr; } //--------------------------------------------------------------------------- @@ -8783,12 +8783,16 @@ void Tokenizer::findGarbageCode() const syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope"); } for (const Token *tok = tokens(); tok; tok = tok->next()) { - if (tok->str() == "{" && isClassStructUnionEnumStart(tok)) { - for (const Token* tok2 = tok->next(); tok2 != tok->link(); tok2 = tok2->next()) { - if (tok2->str() == "{") - tok2 = tok2->link(); - else if (tok2->isKeyword() && nonGlobalKeywords.count(tok2->str()) && !Token::Match(tok2->tokAt(-2), "operator %str%")) - syntaxError(tok2, "keyword '" + tok2->str() + "' is not allowed in class/struct/union/enum scope"); + if (tok->str() == "{") { + if (const Token* start = isClassStructUnionEnumStart(tok)) { + if (Token::simpleMatch(start->tokAt(-1), "->")) + continue; + for (const Token* tok2 = tok->next(); tok2 != tok->link(); tok2 = tok2->next()) { + if (tok2->str() == "{") + tok2 = tok2->link(); + else if (tok2->isKeyword() && nonGlobalKeywords.count(tok2->str()) && !Token::Match(tok2->tokAt(-2), "operator %str%")) + syntaxError(tok2, "keyword '" + tok2->str() + "' is not allowed in class/struct/union/enum scope"); + } } } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index dcbbd0201af..e58be1c0d87 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -7683,6 +7683,12 @@ class TestTokenizer : public TestFixture { ASSERT_NO_THROW(tokenizeAndStringify("struct S { unsigned u:2, :30; };")); // #14393 + ASSERT_NO_THROW(tokenizeAndStringify("struct S {};\n" // #14400 + "auto f(bool b) -> struct S {\n" + " if (b) {}\n" + " return {};\n" + "};\n")); + ignore_errout(); } From 67009b276743c9cef7738a80175bfb0717ac34a6 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 16 Jan 2026 08:16:05 +0100 Subject: [PATCH 2/2] Update tokenize.cpp --- lib/tokenize.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f702947cc95..57f04b5f6e9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -103,14 +103,14 @@ static void skipEnumBody(T *&tok) /** * is tok the start brace { of a class, struct, union, or enum */ -static const Token* isClassStructUnionEnumStart(const Token * tok) +static bool isClassStructUnionEnumStart(const Token * tok) { if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {")) - return nullptr; + return false; const Token * tok2 = tok->previous(); while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|)|;|>|>>")) tok2 = tok2->previous(); - return Token::Match(tok2, "class|struct|union|enum") ? tok2 : nullptr; + return Token::Match(tok2, "class|struct|union|enum") && !Token::simpleMatch(tok2->tokAt(-1), "->"); } //--------------------------------------------------------------------------- @@ -8783,16 +8783,12 @@ void Tokenizer::findGarbageCode() const syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope"); } for (const Token *tok = tokens(); tok; tok = tok->next()) { - if (tok->str() == "{") { - if (const Token* start = isClassStructUnionEnumStart(tok)) { - if (Token::simpleMatch(start->tokAt(-1), "->")) - continue; - for (const Token* tok2 = tok->next(); tok2 != tok->link(); tok2 = tok2->next()) { - if (tok2->str() == "{") - tok2 = tok2->link(); - else if (tok2->isKeyword() && nonGlobalKeywords.count(tok2->str()) && !Token::Match(tok2->tokAt(-2), "operator %str%")) - syntaxError(tok2, "keyword '" + tok2->str() + "' is not allowed in class/struct/union/enum scope"); - } + if (tok->str() == "{" && isClassStructUnionEnumStart(tok)) { + for (const Token* tok2 = tok->next(); tok2 != tok->link(); tok2 = tok2->next()) { + if (tok2->str() == "{") + tok2 = tok2->link(); + else if (tok2->isKeyword() && nonGlobalKeywords.count(tok2->str()) && !Token::Match(tok2->tokAt(-2), "operator %str%")) + syntaxError(tok2, "keyword '" + tok2->str() + "' is not allowed in class/struct/union/enum scope"); } } }