From 1e7f5010eb5e9538b8d822377114035714617609 Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Tue, 28 May 2019 15:32:37 -0400 Subject: [PATCH] template simplifier: fix expansion of template arguments in default parameter instantiation (#1857) --- lib/templatesimplifier.cpp | 98 ++++++++++++++++++++++++----------- lib/templatesimplifier.h | 2 +- test/testsimplifytemplate.cpp | 40 +++----------- test/testtokenize.cpp | 2 +- 4 files changed, 78 insertions(+), 64 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 1dc9e0789..9e5e99e79 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -894,15 +894,21 @@ void TemplateSimplifier::getTemplateInstantiations() void TemplateSimplifier::useDefaultArgumentValues() { - for (TokenAndName &template1 : mTemplateDeclarations) - useDefaultArgumentValues(template1); + for (TokenAndName &declaration : mTemplateDeclarations) + useDefaultArgumentValues(declaration); - for (TokenAndName &template1 : mTemplateForwardDeclarations) - useDefaultArgumentValues(template1); + for (TokenAndName &declaration : mTemplateForwardDeclarations) + useDefaultArgumentValues(declaration); } -void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndName &template1) +void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) { + // Ticket #5762: Skip specialization tokens + // FIXME: should be: if (declaration.isSpecialization() || declaration.isAlias()) + // but there is a problem with functions + if (!declaration.isClass()) + return; + // template parameters with default value has syntax such as: // x = y // this list will contain all the '=' tokens for such arguments @@ -916,19 +922,12 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa // parameter depth std::size_t templateParmDepth = 0; - // the template classname. This will be empty for template functions - std::string classname; + // map type parameter name to index + std::map typeParameterNames; // Scan template declaration.. - for (Token *tok = template1.token; tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "template < >")) { // Ticket #5762: Skip specialization tokens - tok = tok->tokAt(2); - if (0 == templateParmDepth) - break; - continue; - } - - if (tok->str() == "(") { // Ticket #6835 + for (Token *tok = declaration.token; tok; tok = tok->next()) { + if (tok->link()) { // Ticket #6835 tok = tok->link(); continue; } @@ -938,14 +937,16 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa // end of template parameters? if (tok->str() == ">") { - if (Token::Match(tok, "> class|struct|union %name%")) - classname = tok->strAt(2); if (templateParmDepth<2) break; else --templateParmDepth; } + // map type parameter name to index + if (Token::Match(tok, "typename|class %name% ,|>")) + typeParameterNames[tok->strAt(1)] = templatepar - 1; + // next template parameter if (tok->str() == "," && (1 == templateParmDepth)) // Ticket #5823: Properly count parameters ++templatepar; @@ -961,16 +962,43 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa } } } - if (eq.empty() || classname.empty()) + if (eq.empty()) return; // iterate through all template instantiations - for (const TokenAndName &templateInst : mTemplateInstantiations) { - Token *tok = templateInst.token; + for (const TokenAndName &instantiation : mTemplateInstantiations) { + Token *tok = instantiation.token; - if (!Token::simpleMatch(tok, (classname + " <").c_str())) + if (!Token::simpleMatch(tok, (declaration.name + " <").c_str())) continue; + // instantiation arguments.. + std::vector> instantiationArgs; + std::size_t index = 0; + instantiationArgs.resize(1); + const Token *end = instantiation.token->next()->findClosingBracket(); + if (!end) + continue; + for (const Token *tok1 = instantiation.token->tokAt(2); tok1 && tok1!= end; tok1 = tok1->next()) { + if (tok1->link()) { + const Token *endLink = tok1->link(); + do { + instantiationArgs[index].push_back(tok1); + tok1 = tok1->next(); + } while (tok1 && tok1 != endLink); + } else if (tok1->str() == "<") { + const Token *endLink = tok1->findClosingBracket(); + do { + instantiationArgs[index].push_back(tok1); + tok1 = tok1->next(); + } while (tok1 && tok1 != endLink); + } else if (tok1->str() == ",") { + ++index; + instantiationArgs.resize(index + 1); + } else + instantiationArgs[index].push_back(tok1); + } + // count the parameters.. tok = tok->next(); const unsigned int usedpar = templateParameters(tok); @@ -983,7 +1011,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa ++it; while (it != eq.end()) { int indentlevel = 0; - if (usedpar) { + if (usedpar && usedpar <= instantiationArgs.size()) { tok->insertToken(","); tok = tok->next(); } @@ -994,8 +1022,16 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa ++indentlevel; else if (from->str() == ">") --indentlevel; - tok->insertToken(from->str(), from->originalName()); - tok = tok->next(); + auto entry = typeParameterNames.find(from->str()); + if (entry != typeParameterNames.end() && entry->second < instantiationArgs.size()) { + for (const Token *tok1 : instantiationArgs[entry->second]) { + tok->insertToken(tok1->str(), tok1->originalName()); + tok = tok->next(); + } + } else { + tok->insertToken(from->str(), from->originalName()); + tok = tok->next(); + } if (Token::Match(tok, "(|[|{")) links.push(tok); else if (!links.empty() && Token::Match(tok, ")|]|}")) { @@ -1041,7 +1077,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa // don't strip args from uninstantiated templates std::list::iterator ti2 = std::find_if(mTemplateInstantiations.begin(), mTemplateInstantiations.end(), - FindName(template1.name)); + FindName(declaration.name)); if (ti2 == mTemplateInstantiations.end()) continue; @@ -1050,7 +1086,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa eqtok->deleteThis(); // update parameter end pointer - template1.paramEnd = template1.token->next()->findClosingBracket(); + declaration.paramEnd = declaration.token->next()->findClosingBracket(); } } @@ -2360,6 +2396,8 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration( const Token * tok, std::vector & typeParametersInDeclaration) { + assert(tok->strAt(-1) == "<"); + typeParametersInDeclaration.clear(); const Token *end = tok->previous()->findClosingBracket(); for (; tok && tok!= end; tok = tok->next()) { @@ -2367,9 +2405,9 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration( const Token *closing = tok->next()->findClosingBracket(); if (closing) tok = closing->next(); - } - - if (Token::Match(tok, "%name% ,|>|=")) + } else if (tok->link()) + tok = tok->link(); + else if (Token::Match(tok, "%name% ,|>|=")) typeParametersInDeclaration.push_back(tok); } return tok; diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index e7664ce00..a143cf4bc 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -282,7 +282,7 @@ private: * simplify template instantiations (use default argument values) * @param template1 template declaration or forward declaration */ - void useDefaultArgumentValues(TemplateSimplifier::TokenAndName &template1); + void useDefaultArgumentValues(TokenAndName &declaration); /** * Try to locate a matching declaration for each user defined diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index ab8c73d5d..e72efbde0 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -2556,19 +2556,7 @@ private: "static_assert ( sizeof ( e<> ) == sizeof ( e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> ) , \"\" ) ; " "struct e<> { } ; " "struct e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> { } ;"; - const char actual[] = "namespace a { " - "template < typename b , bool > struct c ; " - "} " - "namespace boost { " - "using a :: c ; " - "} " - "using boost :: c ; " - "struct e<> ; " - "struct e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> ; " - "static_assert ( sizeof ( e<> ) == sizeof ( e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> ) , \"\" ) ; " - "struct e<> { } ; " - "struct e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> { } ;"; - TODO_ASSERT_EQUALS(exp, actual, tok(code)); + ASSERT_EQUALS(exp, tok(code)); } { const char code[] = "template struct c;\n" @@ -2580,24 +2568,15 @@ private: "static_assert ( sizeof ( e<> ) == sizeof ( e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> ) , \"\" ) ; " "struct e<> { } ; " "struct e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> { } ;"; - const char actual[] = "template < typename b , bool > struct c ; " - "struct e<> ; " - "struct e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> ; " - "static_assert ( sizeof ( e<> ) == sizeof ( e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> ) , \"\" ) ; " - "struct e<> { } ; " - "struct e{}&&std::is_final{}>,c{}&&std::is_final{}>,int> { } ;"; - TODO_ASSERT_EQUALS(exp, actual, tok(code)); + ASSERT_EQUALS(exp, tok(code)); } { const char code[] = "template struct c{};\n" "c cc;\n"; const char exp[] = "struct c{}&&std::is_final{}> ; " - "c{}&&std::is_final{}> cc ; " + "c{}&&std::is_final{}> cc ; " "struct c{}&&std::is_final{}> { } ;"; - const char actual[] = "struct c{}&&std::is_final{}> ; " - "c{}&&std::is_final{}> cc ; " - "struct c{}&&std::is_final{}> { } ;"; - TODO_ASSERT_EQUALS(exp, actual, tok(code)); + ASSERT_EQUALS(exp, tok(code)); } } @@ -2756,13 +2735,10 @@ private: "template > class thv_table_c {}; " "thv_table_c id_table_m;"; const char exp [] = "template < class T , class U > class DefaultMemory { } ; " - "thv_table_c> id_table_m ; " - "class thv_table_c> { } ;"; - const char curr[] = "template < class T , class U > class DefaultMemory { } ; " - "class thv_table_c> ; " - "thv_table_c> id_table_m ; " - "class thv_table_c> { } ;"; - TODO_ASSERT_EQUALS(exp, curr, tok(code)); + "class thv_table_c> ; " + "thv_table_c> id_table_m ; " + "class thv_table_c> { } ;"; + ASSERT_EQUALS(exp, tok(code)); } { // #8890 diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 29fa498e8..7d5a976b9 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -5214,7 +5214,7 @@ private: "template < class T , T t >\n" "struct S\n" "{ } ;\n" - "S < int , ( T ) 0 > s ;", // current result + "S < int , ( int ) 0 > s ;", // current result tokenizeAndStringify(code)); }