diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 5602a0fca..6742aa041 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -771,7 +771,7 @@ void TemplateSimplifier::getTemplateInstantiations() const Token *tok2 = Token::findmatch(tok, "{|;"); if (tok2 && tok2->str() == "{") tok = tok2->link(); - else if (!isUsing && tok2 && tok2->str() == ";") + else if (tok2 && tok2->str() == ";") tok = const_cast(tok2); } } else if (Token::Match(tok, "template using %name% <")) { @@ -1150,39 +1150,13 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) void TemplateSimplifier::simplifyTemplateAliases() { - std::list::iterator it1, it2, it3; - for (it1 = mTemplateInstantiations.begin(); it1 != mTemplateInstantiations.end();) { - it3 = it1; - TokenAndName &templateAlias = *it1; - ++it1; - Token *startToken = templateAlias.token; - if (!startToken) - continue; - while (Token::Match(startToken->tokAt(-2), "%name% :: %name%")) - startToken = startToken->tokAt(-2); - if (!(Token::Match(startToken->tokAt(-4), "> using %name% = %name% ::|<") || - Token::Match(startToken->tokAt(-5), "> using %name% = typename %name% ::|<"))) - continue; - const bool hasTypename(startToken->strAt(-1) == "typename"); + for (std::list::iterator it1 = mTemplateDeclarations.begin(); it1 != mTemplateDeclarations.end();) { + TokenAndName &aliasDeclaration = *it1; - // Get start token for alias - startToken = startToken->tokAt(hasTypename ? -6 : -5); - while (Token::Match(startToken, "%name%|<|>|>>|,")) - startToken = startToken->previous(); - // handle case where 'template' is first token - if (!startToken) { - if (!Token::simpleMatch(mTokenList.front(), "template <")) - continue; - } else if (!Token::Match(startToken, "[;{}] template <")) + if (!aliasDeclaration.isAlias()) { + ++it1; continue; - - std::list::iterator it5 = std::find_if(mTemplateDeclarations.begin(), - mTemplateDeclarations.end(), - FindToken(!startToken ? mTokenList.front() : startToken->next())); - if (it5 == mTemplateDeclarations.end()) - continue; - - TokenAndName &aliasDeclaration = *it5; + } // alias parameters.. std::vector aliasParameters; @@ -1192,15 +1166,19 @@ void TemplateSimplifier::simplifyTemplateAliases() aliasParameterNames[aliasParameters[argnr]->str()] = argnr; // Look for alias usages.. - const Token *endToken = nullptr; - for (it2 = it1; it2 != mTemplateInstantiations.end(); ++it2) { + bool found = false; + for (std::list::iterator it2 = mTemplateInstantiations.begin(); it2 != mTemplateInstantiations.end();) { TokenAndName &aliasUsage = *it2; - if (!aliasUsage.token || aliasUsage.fullName != aliasDeclaration.fullName) + if (!aliasUsage.token || aliasUsage.fullName != aliasDeclaration.fullName) { + ++it2; continue; + } // don't recurse - if (aliasDeclaration.isAliasToken(aliasUsage.token)) + if (aliasDeclaration.isAliasToken(aliasUsage.token)) { + ++it2; continue; + } std::vector> args; Token *tok2 = aliasUsage.token->tokAt(2); @@ -1221,37 +1199,32 @@ void TemplateSimplifier::simplifyTemplateAliases() break; } } - if (!tok2 || tok2->str() != ">" || args.size() != aliasParameters.size()) + if (!tok2 || tok2->str() != ">" || args.size() != aliasParameters.size()) { + ++it2; continue; - - // Replace template alias code.. - aliasUsage.name = templateAlias.name; - aliasUsage.fullName = templateAlias.fullName; - aliasUsage.scope = templateAlias.scope; - const Token *temp = aliasDeclaration.aliasStartToken(); - if (temp->str() == "typename") - temp = temp->next(); - std::stack links; - while (temp && temp != templateAlias.token) { - aliasUsage.token->insertToken(temp->str(), "", true); - - Token * previous = aliasUsage.token->previous(); - if (Token::Match(previous, "(|[|{")) - links.push(previous); - else if (!links.empty() && Token::Match(previous, ")|]|}")) { - Token::createMutualLinks(links.top(), previous); - links.pop(); - } - - temp = temp->next(); } - aliasUsage.token->str(templateAlias.token->str()); - tok2 = aliasUsage.token->next(); // the '<' - const Token * const endToken1 = templateAlias.token->next()->findClosingBracket(); - const Token * const endToken2 = TokenList::copyTokens(tok2, templateAlias.token->tokAt(2), endToken1->previous(), false)->next(); - for (const Token *tok1 = templateAlias.token->next(); tok2 != endToken2; tok1 = tok1->next(), tok2 = tok2->next()) { - if (!tok2->isName()) + // copy template-id from declaration to after instantiation + Token * dst = aliasUsage.token->next()->findClosingBracket(); + Token * end = TokenList::copyTokens(dst, aliasDeclaration.aliasStartToken(), aliasDeclaration.aliasEndToken()->previous(), false)->next(); + + // replace parameters + for (Token *tok1 = dst->next(); tok1 != end; tok1 = tok1->next()) { + if (!tok1->isName()) + continue; + if (aliasParameterNames.find(tok1->str()) != aliasParameterNames.end()) { + const unsigned int argnr = aliasParameterNames[tok1->str()]; + const Token * const fromStart = args[argnr].first; + const Token * const fromEnd = args[argnr].second->previous(); + TokenList::copyTokens(tok1, fromStart, fromEnd, true); + tok1->deleteThis(); + } else if (tok1->str() == "typename") + tok1->deleteThis(); + } + + // add new instantiations + for (Token *tok1 = dst->next(); tok1 != end; tok1 = tok1->next()) { + if (!tok1->isName()) continue; if (aliasParameterNames.find(tok2->str()) == aliasParameterNames.end()) { // Create template instance.. @@ -1262,53 +1235,32 @@ void TemplateSimplifier::simplifyTemplateAliases() if (it != mTemplateInstantiations.end()) addInstantiation(tok2, it->scope); } - continue; } - const unsigned int argnr = aliasParameterNames[tok2->str()]; - const Token * const fromStart = args[argnr].first; - const Token * const fromEnd = args[argnr].second->previous(); - Token * const destToken = tok2; - tok2 = TokenList::copyTokens(tok2, fromStart, fromEnd, true); - if (tok2 == destToken->next()) - tok2 = destToken; - destToken->deleteThis(); } - endToken = endToken1->next(); - while (endToken->str() != ";") - endToken = endToken->next(); + // erase the instantiation tokens + eraseTokens(aliasUsage.token->previous(), dst->next()); + found = true; - // Remove alias usage code (parameters) - Token::eraseTokens(tok2->previous(), args.back().second); + // erase this instantiation + it2 = mTemplateInstantiations.erase(it2); } - if (endToken) { - // Remove all template instantiations in template alias - for (const Token *tok = aliasDeclaration.paramEnd->tokAt(4); tok != endToken; tok = tok->next()) { - if (!Token::Match(tok, "%name% <")) - continue; - std::list::iterator it = std::find_if(mTemplateInstantiations.begin(), - mTemplateInstantiations.end(), - FindToken(tok)); - if (it == mTemplateInstantiations.end()) - continue; - std::list::iterator next = it; - ++next; - if (it == it1) - it1 = next; - mTemplateInstantiations.erase(it,next); - } - if (startToken) - eraseTokens(startToken, endToken->next() ? endToken->next() : endToken); + if (found) { + Token *end = const_cast(aliasDeclaration.aliasEndToken()); + + // remove declaration tokens + if (aliasDeclaration.token->previous()) + eraseTokens(aliasDeclaration.token->previous(), end->next() ? end->next() : end); else { - eraseTokens(mTokenList.front(), endToken->next() ? endToken->next() : endToken); + eraseTokens(mTokenList.front(), end->next() ? end->next() : end); deleteToken(mTokenList.front()); } // remove declaration - mTemplateDeclarations.erase(it5); + it1 = mTemplateDeclarations.erase(it1); } else - mTemplateInstantiations.erase(it3); + ++it1; } } @@ -3298,7 +3250,7 @@ void TemplateSimplifier::simplifyTemplates( } } - // TODO: 2 is not the ideal number of loops. + // TODO: 3 is not the ideal number of loops. // We should loop until the number of declarations is 0 but we can't // do that until we instantiate unintstantiated templates with their symbolic types. // That will allow the uninstantiated template code to be removed from the symbol database. @@ -3306,7 +3258,7 @@ void TemplateSimplifier::simplifyTemplates( // the uninstantiated template code in the symbol database can't be removed until #8768 // is fixed. - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 3; ++i) { if (i) { // it may take more than one pass to simplify type aliases while (mTokenizer->simplifyUsing()) diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 827ca622b..54ccab07f 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -151,6 +151,7 @@ private: TEST_CASE(template111); // crash TEST_CASE(template112); // #9146 syntax error TEST_CASE(template113); + TEST_CASE(template114); // #9155 TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) @@ -188,6 +189,7 @@ private: TEST_CASE(templateAlias2); TEST_CASE(templateAlias3); // #8315 TEST_CASE(templateAlias4); // #9070 + TEST_CASE(templateAlias5); // Test TemplateSimplifier::instantiateMatch TEST_CASE(instantiateMatch); @@ -2555,7 +2557,7 @@ private: "template < typename > struct c ; " "struct e ; " "} " - "e foo ; " + "e :: g foo ; " "struct e { " "bool h ; h = a < b::g> > :: h ; " "} ; " @@ -2680,6 +2682,20 @@ private: } } + void template114() { // #9155 + const char code[] = "template struct b {};\n" + "template struct c;\n" + "template struct d : b{}> {};\n" + "template struct e;\n" + "template using f = typename e>::g>::h;"; + const char exp[] = "template < typename a , a > struct b { } ; " + "template < typename > struct c ; " + "template < typename > struct d : b < bool , std :: is_polymorphic < int > { } > { } ; " + "template < bool > struct e ; " + "template < typename a > using f = typename e < c < d < a > > :: g > :: h ;"; + ASSERT_EQUALS(exp, tok(code)); + } + void template_specialization_1() { // #7868 - template specialization template struct S> {..}; const char code[] = "template struct C {};\n" "template struct S {a};\n" @@ -3678,6 +3694,16 @@ private: ASSERT_EQUALS(expected, tok(code)); } + void templateAlias5() { + const char code[] = "template using A = int;\n" + "template using B = T;\n" + "A a;\n" + "B b;"; + const char expected[] = "int a ; " + "char b ;"; + ASSERT_EQUALS(expected, tok(code)); + } + unsigned int instantiateMatch(const char code[], const std::size_t numberOfArguments, const char patternAfter[]) { Tokenizer tokenizer(&settings, this); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 83cd3c44f..1d9ea705b 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -4858,7 +4858,6 @@ private: Tokenizer tokenizer(&settings0, this); std::istringstream istr(code); tokenizer.tokenize(istr, "test.cpp"); - ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> > ;")->link()); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> ;")->link()); }