Refactored simplifyTemplateAliases to iterate over template type aliases rather than instantiations. This fixed template type aliases that were not templates. Don't instantiate templates in template type aliases. They will get instantiated once the type alias is instantiated. This required increasing the template simplifier pass count to 3 so one of the existing tests continued to work.
This commit is contained in:
parent
4939e0c308
commit
2a4b28c267
|
@ -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<Token *>(tok2);
|
||||
}
|
||||
} else if (Token::Match(tok, "template using %name% <")) {
|
||||
|
@ -1150,39 +1150,13 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
|
|||
|
||||
void TemplateSimplifier::simplifyTemplateAliases()
|
||||
{
|
||||
std::list<TokenAndName>::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<TokenAndName>::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<TokenAndName>::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<const Token *> 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<TokenAndName>::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<std::pair<Token *, Token *>> 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<Token *> 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<TokenAndName>::iterator it = std::find_if(mTemplateInstantiations.begin(),
|
||||
mTemplateInstantiations.end(),
|
||||
FindToken(tok));
|
||||
if (it == mTemplateInstantiations.end())
|
||||
continue;
|
||||
std::list<TokenAndName>::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<Token *>(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())
|
||||
|
|
|
@ -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 <typename T> struct S<C<T>> {..};
|
||||
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
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<int> ; "
|
||||
"} "
|
||||
"e<int> foo ; "
|
||||
"e<int> :: g foo ; "
|
||||
"struct e<int> { "
|
||||
"bool h ; h = a < b<c<int>::g> > :: h ; "
|
||||
"} ; "
|
||||
|
@ -2680,6 +2682,20 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void template114() { // #9155
|
||||
const char code[] = "template <typename a, a> struct b {};\n"
|
||||
"template <typename> struct c;\n"
|
||||
"template <typename> struct d : b<bool, std::is_polymorphic<int>{}> {};\n"
|
||||
"template <bool> struct e;\n"
|
||||
"template <typename a> using f = typename e<c<d<a>>::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 <typename T> struct S<C<T>> {..};
|
||||
const char code[] = "template <typename T> struct C {};\n"
|
||||
"template <typename T> struct S {a};\n"
|
||||
|
@ -3678,6 +3694,16 @@ private:
|
|||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void templateAlias5() {
|
||||
const char code[] = "template<typename T> using A = int;\n"
|
||||
"template<typename T> using B = T;\n"
|
||||
"A<char> a;\n"
|
||||
"B<char> 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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue