From d27dfca75aa58903732ed13f4c26426a1bac1333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 28 Aug 2025 13:58:58 +0200 Subject: [PATCH 1/2] Fix #14095 (TemplateSimplifier: store location of template argument token) --- lib/templatesimplifier.cpp | 11 +++++----- lib/token.cpp | 7 ++++++ lib/token.h | 16 ++++++++++++-- lib/tokenize.cpp | 6 +++++- test/testsimplifytemplate.cpp | 40 +++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 8 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index dfb4eb6d164..7f64a10d7e8 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -1766,7 +1766,7 @@ void TemplateSimplifier::expandTemplate( dst->previous()->linenr(start->linenr()); dst->previous()->column(start->column()); Token *previous = dst->previous(); - previous->isTemplateArg(true); + previous->templateArgFrom(typetok); previous->isSigned(typetok->isSigned()); previous->isUnsigned(typetok->isUnsigned()); previous->isLong(typetok->isLong()); @@ -2016,7 +2016,7 @@ void TemplateSimplifier::expandTemplate( Token::createMutualLinks(brackets1.top(), back); brackets1.pop(); } - back->isTemplateArg(true); + back->templateArgFrom(typetok); back->isUnsigned(typetok->isUnsigned()); back->isSigned(typetok->isSigned()); back->isLong(typetok->isLong()); @@ -2111,16 +2111,17 @@ void TemplateSimplifier::expandTemplate( if (Token::Match(declTok->previous(), "[<,]")) { const Token* typetok = mTypesUsedInTemplateInstantiation[itype].token(); mTokenList.addtoken("(", declTok); + mTokenList.back()->templateArgFrom(declTok); Token* const par1 = mTokenList.back(); while (declTok != typeParametersInDeclaration[itype]) { mTokenList.addtoken(declTok); + mTokenList.back()->templateArgFrom(declTok); declTok = declTok->next(); } mTokenList.addtoken(")", declTok); + mTokenList.back()->templateArgFrom(declTok); Token::createMutualLinks(par1, mTokenList.back()); mTokenList.addtoken(typetok, tok3); - for (Token* t = par1; t; t = t->next()) - t->isTemplateArg(true); continue; } } @@ -2174,7 +2175,7 @@ void TemplateSimplifier::expandTemplate( brackets1.pop(); } if (copy) - back->isTemplateArg(true); + back->templateArgFrom(typetok); } if (pointerType && Token::simpleMatch(beforeTypeToken, "const")) { mTokenList.addtoken(beforeTypeToken); diff --git a/lib/token.cpp b/lib/token.cpp index 44e62e21507..c4967ceb1d5 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2720,3 +2720,10 @@ Token* findLambdaEndScope(Token* tok) const Token* findLambdaEndScope(const Token* tok) { return findLambdaEndScope(const_cast(tok)); } + +void Token::templateArgFrom(const Token* fromToken) { + setFlag(fIsTemplateArg, fromToken != nullptr); + mImpl->mTemplateArgFileIndex = fromToken ? fromToken->mImpl->mFileIndex : -1; + mImpl->mTemplateArgLineNumber = fromToken ? fromToken->mImpl->mLineNumber : -1; + mImpl->mTemplateArgColumn = fromToken ? fromToken->mImpl->mColumn : -1; +} diff --git a/lib/token.h b/lib/token.h index b2c433af164..b23fb2785d4 100644 --- a/lib/token.h +++ b/lib/token.h @@ -70,6 +70,11 @@ struct TokenImpl { nonneg int mColumn{}; nonneg int mExprId{}; + // original template argument location + int mTemplateArgFileIndex{-1}; + int mTemplateArgLineNumber{-1}; + int mTemplateArgColumn{-1}; + /** * A value from 0-100 that provides a rough idea about where in the token * list this token is located. @@ -824,8 +829,15 @@ class CPPCHECKLIB Token { bool isTemplateArg() const { return getFlag(fIsTemplateArg); } - void isTemplateArg(const bool value) { - setFlag(fIsTemplateArg, value); + void templateArgFrom(const Token* fromToken); + int templateArgFileIndex() const { + return mImpl->mTemplateArgFileIndex; + } + int templateArgLineNumber() const { + return mImpl->mTemplateArgLineNumber; + } + int templateArgColumn() const { + return mImpl->mTemplateArgColumn; } const std::string& getMacroName() const { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 8e60a31fede..d5688207c5d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6079,8 +6079,12 @@ void Tokenizer::dump(std::ostream &out) const outs += " externLang=\"C\""; if (tok->isExpandedMacro()) outs += " macroName=\"" + tok->getMacroName() + "\""; - if (tok->isTemplateArg()) + if (tok->isTemplateArg()) { outs += " isTemplateArg=\"true\""; + outs += " templateArgFileIndex=\"" + std::to_string(tok->templateArgFileIndex()) + "\""; + outs += " templateArgLineNumber=\"" + std::to_string(tok->templateArgLineNumber()) + "\""; + outs += " templateArgColumn=\"" + std::to_string(tok->templateArgColumn()) + "\""; + } if (tok->isRemovedVoidParameter()) outs += " isRemovedVoidParameter=\"true\""; if (tok->isSplittedVarDeclComma()) diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 1796d54e68c..7c6736f291a 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -314,6 +314,8 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(explicitBool2); TEST_CASE(templateArgPreserveType); // #13882 - type of template argument + + TEST_CASE(dumpTemplateArgFrom); } struct CheckOptions @@ -333,6 +335,20 @@ class TestSimplifyTemplate : public TestFixture { return tokenizer.tokens()->stringifyList(nullptr, true); } +#define dump(...) dump_(__FILE__, __LINE__, __VA_ARGS__) + template + std::string dump_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { + const Settings settings1 = settingsBuilder(settings).library("std.cfg").debugwarnings(options.debugwarnings).build(); + SimpleTokenizer tokenizer(settings1, *this); + + ASSERT_LOC(tokenizer.tokenize(code), file, line); + + std::ostringstream ostr; + (tokenizer.dump)(ostr); + + return ostr.str(); + } + void template1() { const char code[] = "template T f(T val) { T a; }\n" "f(10);"; @@ -6623,6 +6639,30 @@ class TestSimplifyTemplate : public TestFixture { "class Test<64> { uint32_t i ; i = ( uint32_t ) 64 ; } ;", tok(code)); } + + void dumpTemplateArgFrom() { + const char code[] = "template void foo(T t) {}\n" + "foo(23);"; + const std::string d = dump(code); + ASSERT(!d.empty()); + + // Assert that first 'int' token has templateArg location info + const std::string::size_type strpos1 = d.find(" str=\"int\" "); + ASSERT(strpos1 < d.size()); + const std::string::size_type endpos1 = d.find('>', strpos1); + const std::string::size_type templateArgPos1 = d.find(" templateArgFileIndex=\"0\" templateArgLineNumber=\"2\" templateArgColumn=\"5\""); + ASSERT(templateArgPos1 > strpos1 && templateArgPos1 < endpos1); + + // Assert that second 'int' token has templateArg location info + const std::string::size_type strpos2 = d.find(" str=\"int\" ", endpos1); + ASSERT(strpos2 < d.size()); + const std::string::size_type endpos2 = d.find('>', strpos2); + const std::string::size_type templateArgPos2 = d.find(" templateArgFileIndex=\"0\" templateArgLineNumber=\"2\" templateArgColumn=\"5\"", endpos1); + ASSERT(templateArgPos2 > strpos2 && templateArgPos2 < endpos2); + + // Assert there is no further unexpected templateArg location info + ASSERT(d.find(" templateArg", endpos2) == std::string::npos); + } }; REGISTER_TEST(TestSimplifyTemplate) From d0fb538531cc933e503620da05976e7798a1cec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 28 Aug 2025 14:17:25 +0200 Subject: [PATCH 2/2] fix TestValueFlow failure --- lib/templatesimplifier.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 7f64a10d7e8..18cec14c171 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -2111,17 +2111,16 @@ void TemplateSimplifier::expandTemplate( if (Token::Match(declTok->previous(), "[<,]")) { const Token* typetok = mTypesUsedInTemplateInstantiation[itype].token(); mTokenList.addtoken("(", declTok); - mTokenList.back()->templateArgFrom(declTok); Token* const par1 = mTokenList.back(); while (declTok != typeParametersInDeclaration[itype]) { mTokenList.addtoken(declTok); - mTokenList.back()->templateArgFrom(declTok); declTok = declTok->next(); } mTokenList.addtoken(")", declTok); - mTokenList.back()->templateArgFrom(declTok); Token::createMutualLinks(par1, mTokenList.back()); mTokenList.addtoken(typetok, tok3); + for (Token* t = par1; t; t = t->next()) + t->templateArgFrom(typetok); continue; } }