From c4d35a2392b4000b6551ce48acb5e7bc0b1819b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 10 Sep 2025 11:02:35 +0200 Subject: [PATCH 1/6] update test --- test/cli/other_test.py | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 243f600b5a6..4e30d5e08d7 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -3415,6 +3415,70 @@ def test_check_unused_templates_func(tmp_path): # #13714 (void)(*((int*)0)); } +class S { +public: + template + void f_t_3() + { + (void)(*((int*)0)); + } +} + +template +static inline void f_t_4() +{ + (void)(*((int*)0)); +} + +template +const void *f_t_5() +{ + (void)(*((int*)0)); +} + +template +void f_t_6() __attribute__((noreturn)) +{ + (void)(*((int*)0)); +} + +template +__attribute__((noreturn)) void f_t_7() +{ + (void)(*((int*)0)); +} + +template +__declspec(noreturn) void f_t_8() +{ + (void)(*((int*)0)); +} + +template +[[noreturn]] void f_t_9() +{ + (void)(*((int*)0)); +} + +template +void f_t_10() noexcept(true) +{ + (void)(*((int*)0)); +} + +template +void f_t_11() throw(true) +{ + (void)(*((int*)0)); +} + +struct S { + template + void f_t_12() const { + (void)(*((int*)0)); + } +}; + void f() {} """) From 564bddbe76025da565a7217e92e664c397559fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 8 Sep 2025 11:24:10 +0200 Subject: [PATCH 2/6] fix #14118 --- lib/tokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 6f9cf90a852..67c08ce713c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6518,7 +6518,7 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() } } - if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) { + if (!tok->previous() || Token::Match(tok->previous(), "[;{}:]")) { // Remove unused function declarations if (isIncluded && removeUnusedIncludedFunctions) { while (true) { From e1d786754b03bac298bd3cf0f85b11c31e754884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 8 Sep 2025 13:10:58 +0200 Subject: [PATCH 3/6] fix #14117 --- lib/tokenize.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 67c08ce713c..d8030f16251 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6551,7 +6551,7 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) { if (Token::Match(tok, "template < %name%")) { - const Token *closingBracket = tok->next()->findClosingBracket(); + Token *closingBracket = tok->next()->findClosingBracket(); if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) { const Token *endToken = closingBracket->tokAt(3); if (endToken->str() == ":") { @@ -6565,11 +6565,68 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() Token::eraseTokens(tok, endToken); tok->deleteThis(); } - } else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) { - const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next(); - Token::eraseTokens(tok, endToken); - tok->deleteThis(); - goBack = true; + } else { + Token *funcTok = closingBracket->next(); + while (funcTok) { + if (Token::Match(funcTok, "__declspec|__attribute__ (")) { + funcTok = funcTok->linkAt(1); + if (funcTok) { + funcTok = funcTok->next(); + } + continue; + } + if (Token::Match(funcTok, "[ [")) { + funcTok = funcTok->link(); + if (funcTok) { + funcTok = funcTok->next(); + } + continue; + } + if (Token::Match(funcTok, "static|inline|const|%type%|&|&&|*") && !Token::Match(funcTok, "%name% (")) { + funcTok = funcTok->next(); + continue; + } + break; + } + if (!Token::Match(funcTok, "%name% (")) { + tok = funcTok; + continue; + } + funcTok = funcTok->linkAt(1); + if (funcTok) { + funcTok = funcTok->next(); + } + while (funcTok) { + if (Token::Match(funcTok, "__declspec|__attribute__|throw|noexcept (")) { + funcTok = funcTok->linkAt(1); + if (funcTok) { + funcTok = funcTok->next(); + } + continue; + } + if (Token::Match(funcTok, "[ [")) { + funcTok = funcTok->link(); + if (funcTok) { + funcTok = funcTok->next(); + } + continue; + } + if (Token::Match(funcTok, "const|volatile|&|&&")) { + funcTok = funcTok->next(); + continue; + } + break; + } + if (!Token::simpleMatch(funcTok, "{")) { + tok = funcTok; + continue; + } + funcTok = funcTok->link(); + if (funcTok) { + Token::eraseTokens(tok, funcTok->next()); + tok->deleteThis(); + goBack = true; + } } } } From 41671ba23ad6054358a857c46408a842be81237a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 10 Sep 2025 13:58:04 +0200 Subject: [PATCH 4/6] move invocation of simplifyHeadersAndUnusedTemplates --- lib/tokenize.cpp | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d8030f16251..a518f0cb3ee 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5725,8 +5725,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) simplifyFunctionTryCatch(); - simplifyHeadersAndUnusedTemplates(); - // Remove __asm.. simplifyAsm(); @@ -5754,6 +5752,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // remove __attribute__((?)) simplifyAttribute(); + simplifyHeadersAndUnusedTemplates(); + validate(); // Bail out if code is garbage @@ -6568,20 +6568,6 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() } else { Token *funcTok = closingBracket->next(); while (funcTok) { - if (Token::Match(funcTok, "__declspec|__attribute__ (")) { - funcTok = funcTok->linkAt(1); - if (funcTok) { - funcTok = funcTok->next(); - } - continue; - } - if (Token::Match(funcTok, "[ [")) { - funcTok = funcTok->link(); - if (funcTok) { - funcTok = funcTok->next(); - } - continue; - } if (Token::Match(funcTok, "static|inline|const|%type%|&|&&|*") && !Token::Match(funcTok, "%name% (")) { funcTok = funcTok->next(); continue; @@ -6597,20 +6583,13 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() funcTok = funcTok->next(); } while (funcTok) { - if (Token::Match(funcTok, "__declspec|__attribute__|throw|noexcept (")) { + if (Token::Match(funcTok, "throw|noexcept (")) { funcTok = funcTok->linkAt(1); if (funcTok) { funcTok = funcTok->next(); } continue; } - if (Token::Match(funcTok, "[ [")) { - funcTok = funcTok->link(); - if (funcTok) { - funcTok = funcTok->next(); - } - continue; - } if (Token::Match(funcTok, "const|volatile|&|&&")) { funcTok = funcTok->next(); continue; From eb4a341fb75631e8179d6cca475132155173958d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 10 Sep 2025 13:58:30 +0200 Subject: [PATCH 5/6] handle constexpr --- lib/tokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index a518f0cb3ee..900a97d6e5d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6568,7 +6568,7 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() } else { Token *funcTok = closingBracket->next(); while (funcTok) { - if (Token::Match(funcTok, "static|inline|const|%type%|&|&&|*") && !Token::Match(funcTok, "%name% (")) { + if (Token::Match(funcTok, "constexpr|static|inline|const|%type%|&|&&|*") && !Token::Match(funcTok, "%name% (")) { funcTok = funcTok->next(); continue; } From 5ff2bec06734ced048346b6a60f75b7fd93c5b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 12 May 2026 17:43:35 +0200 Subject: [PATCH 6/6] handle templated return types --- lib/tokenize.cpp | 13 ++++++++++++- test/cli/other_test.py | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 900a97d6e5d..69c937cfb30 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6568,12 +6568,23 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() } else { Token *funcTok = closingBracket->next(); while (funcTok) { - if (Token::Match(funcTok, "constexpr|static|inline|const|%type%|&|&&|*") && !Token::Match(funcTok, "%name% (")) { + if (Token::Match(funcTok, "::|constexpr|static|inline|const|%type%|&|&&|*") && !Token::Match(funcTok, "%name% (")) { funcTok = funcTok->next(); continue; } + if (Token::simpleMatch(funcTok, "<")) { + funcTok = funcTok->findClosingBracket(); + if (funcTok) { + funcTok = funcTok->next(); + } else { + break; + } + continue; + } break; } + if (!funcTok) + break; if (!Token::Match(funcTok, "%name% (")) { tok = funcTok; continue; diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 4e30d5e08d7..7a848b04960 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -3479,6 +3479,12 @@ class S { } }; +template +std::vector f_t_13() { + (void)(*((int*)0)); + return {}; +} + void f() {} """)