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, "{|;");
|
const Token *tok2 = Token::findmatch(tok, "{|;");
|
||||||
if (tok2 && tok2->str() == "{")
|
if (tok2 && tok2->str() == "{")
|
||||||
tok = tok2->link();
|
tok = tok2->link();
|
||||||
else if (!isUsing && tok2 && tok2->str() == ";")
|
else if (tok2 && tok2->str() == ";")
|
||||||
tok = const_cast<Token *>(tok2);
|
tok = const_cast<Token *>(tok2);
|
||||||
}
|
}
|
||||||
} else if (Token::Match(tok, "template using %name% <")) {
|
} else if (Token::Match(tok, "template using %name% <")) {
|
||||||
|
@ -1150,39 +1150,13 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
|
||||||
|
|
||||||
void TemplateSimplifier::simplifyTemplateAliases()
|
void TemplateSimplifier::simplifyTemplateAliases()
|
||||||
{
|
{
|
||||||
std::list<TokenAndName>::iterator it1, it2, it3;
|
for (std::list<TokenAndName>::iterator it1 = mTemplateDeclarations.begin(); it1 != mTemplateDeclarations.end();) {
|
||||||
for (it1 = mTemplateInstantiations.begin(); it1 != mTemplateInstantiations.end();) {
|
TokenAndName &aliasDeclaration = *it1;
|
||||||
it3 = it1;
|
|
||||||
TokenAndName &templateAlias = *it1;
|
if (!aliasDeclaration.isAlias()) {
|
||||||
++it1;
|
++it1;
|
||||||
Token *startToken = templateAlias.token;
|
|
||||||
if (!startToken)
|
|
||||||
continue;
|
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");
|
|
||||||
|
|
||||||
// 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 <"))
|
|
||||||
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..
|
// alias parameters..
|
||||||
std::vector<const Token *> aliasParameters;
|
std::vector<const Token *> aliasParameters;
|
||||||
|
@ -1192,15 +1166,19 @@ void TemplateSimplifier::simplifyTemplateAliases()
|
||||||
aliasParameterNames[aliasParameters[argnr]->str()] = argnr;
|
aliasParameterNames[aliasParameters[argnr]->str()] = argnr;
|
||||||
|
|
||||||
// Look for alias usages..
|
// Look for alias usages..
|
||||||
const Token *endToken = nullptr;
|
bool found = false;
|
||||||
for (it2 = it1; it2 != mTemplateInstantiations.end(); ++it2) {
|
for (std::list<TokenAndName>::iterator it2 = mTemplateInstantiations.begin(); it2 != mTemplateInstantiations.end();) {
|
||||||
TokenAndName &aliasUsage = *it2;
|
TokenAndName &aliasUsage = *it2;
|
||||||
if (!aliasUsage.token || aliasUsage.fullName != aliasDeclaration.fullName)
|
if (!aliasUsage.token || aliasUsage.fullName != aliasDeclaration.fullName) {
|
||||||
|
++it2;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// don't recurse
|
// don't recurse
|
||||||
if (aliasDeclaration.isAliasToken(aliasUsage.token))
|
if (aliasDeclaration.isAliasToken(aliasUsage.token)) {
|
||||||
|
++it2;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<Token *, Token *>> args;
|
std::vector<std::pair<Token *, Token *>> args;
|
||||||
Token *tok2 = aliasUsage.token->tokAt(2);
|
Token *tok2 = aliasUsage.token->tokAt(2);
|
||||||
|
@ -1221,37 +1199,32 @@ void TemplateSimplifier::simplifyTemplateAliases()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tok2 || tok2->str() != ">" || args.size() != aliasParameters.size())
|
if (!tok2 || tok2->str() != ">" || args.size() != aliasParameters.size()) {
|
||||||
|
++it2;
|
||||||
continue;
|
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();
|
// copy template-id from declaration to after instantiation
|
||||||
}
|
Token * dst = aliasUsage.token->next()->findClosingBracket();
|
||||||
aliasUsage.token->str(templateAlias.token->str());
|
Token * end = TokenList::copyTokens(dst, aliasDeclaration.aliasStartToken(), aliasDeclaration.aliasEndToken()->previous(), false)->next();
|
||||||
|
|
||||||
tok2 = aliasUsage.token->next(); // the '<'
|
// replace parameters
|
||||||
const Token * const endToken1 = templateAlias.token->next()->findClosingBracket();
|
for (Token *tok1 = dst->next(); tok1 != end; tok1 = tok1->next()) {
|
||||||
const Token * const endToken2 = TokenList::copyTokens(tok2, templateAlias.token->tokAt(2), endToken1->previous(), false)->next();
|
if (!tok1->isName())
|
||||||
for (const Token *tok1 = templateAlias.token->next(); tok2 != endToken2; tok1 = tok1->next(), tok2 = tok2->next()) {
|
continue;
|
||||||
if (!tok2->isName())
|
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;
|
continue;
|
||||||
if (aliasParameterNames.find(tok2->str()) == aliasParameterNames.end()) {
|
if (aliasParameterNames.find(tok2->str()) == aliasParameterNames.end()) {
|
||||||
// Create template instance..
|
// Create template instance..
|
||||||
|
@ -1262,53 +1235,32 @@ void TemplateSimplifier::simplifyTemplateAliases()
|
||||||
if (it != mTemplateInstantiations.end())
|
if (it != mTemplateInstantiations.end())
|
||||||
addInstantiation(tok2, it->scope);
|
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();
|
// erase the instantiation tokens
|
||||||
while (endToken->str() != ";")
|
eraseTokens(aliasUsage.token->previous(), dst->next());
|
||||||
endToken = endToken->next();
|
found = true;
|
||||||
|
|
||||||
// Remove alias usage code (parameters)
|
// erase this instantiation
|
||||||
Token::eraseTokens(tok2->previous(), args.back().second);
|
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)
|
if (found) {
|
||||||
eraseTokens(startToken, endToken->next() ? endToken->next() : endToken);
|
Token *end = const_cast<Token *>(aliasDeclaration.aliasEndToken());
|
||||||
|
|
||||||
|
// remove declaration tokens
|
||||||
|
if (aliasDeclaration.token->previous())
|
||||||
|
eraseTokens(aliasDeclaration.token->previous(), end->next() ? end->next() : end);
|
||||||
else {
|
else {
|
||||||
eraseTokens(mTokenList.front(), endToken->next() ? endToken->next() : endToken);
|
eraseTokens(mTokenList.front(), end->next() ? end->next() : end);
|
||||||
deleteToken(mTokenList.front());
|
deleteToken(mTokenList.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove declaration
|
// remove declaration
|
||||||
mTemplateDeclarations.erase(it5);
|
it1 = mTemplateDeclarations.erase(it1);
|
||||||
} else
|
} 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
|
// 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.
|
// 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.
|
// 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
|
// the uninstantiated template code in the symbol database can't be removed until #8768
|
||||||
// is fixed.
|
// is fixed.
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
if (i) {
|
if (i) {
|
||||||
// it may take more than one pass to simplify type aliases
|
// it may take more than one pass to simplify type aliases
|
||||||
while (mTokenizer->simplifyUsing())
|
while (mTokenizer->simplifyUsing())
|
||||||
|
|
|
@ -151,6 +151,7 @@ private:
|
||||||
TEST_CASE(template111); // crash
|
TEST_CASE(template111); // crash
|
||||||
TEST_CASE(template112); // #9146 syntax error
|
TEST_CASE(template112); // #9146 syntax error
|
||||||
TEST_CASE(template113);
|
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_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_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)
|
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
|
@ -188,6 +189,7 @@ private:
|
||||||
TEST_CASE(templateAlias2);
|
TEST_CASE(templateAlias2);
|
||||||
TEST_CASE(templateAlias3); // #8315
|
TEST_CASE(templateAlias3); // #8315
|
||||||
TEST_CASE(templateAlias4); // #9070
|
TEST_CASE(templateAlias4); // #9070
|
||||||
|
TEST_CASE(templateAlias5);
|
||||||
|
|
||||||
// Test TemplateSimplifier::instantiateMatch
|
// Test TemplateSimplifier::instantiateMatch
|
||||||
TEST_CASE(instantiateMatch);
|
TEST_CASE(instantiateMatch);
|
||||||
|
@ -2555,7 +2557,7 @@ private:
|
||||||
"template < typename > struct c ; "
|
"template < typename > struct c ; "
|
||||||
"struct e<int> ; "
|
"struct e<int> ; "
|
||||||
"} "
|
"} "
|
||||||
"e<int> foo ; "
|
"e<int> :: g foo ; "
|
||||||
"struct e<int> { "
|
"struct e<int> { "
|
||||||
"bool h ; h = a < b<c<int>::g> > :: h ; "
|
"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>> {..};
|
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||||
const char code[] = "template <typename T> struct C {};\n"
|
const char code[] = "template <typename T> struct C {};\n"
|
||||||
"template <typename T> struct S {a};\n"
|
"template <typename T> struct S {a};\n"
|
||||||
|
@ -3678,6 +3694,16 @@ private:
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
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[]) {
|
unsigned int instantiateMatch(const char code[], const std::size_t numberOfArguments, const char patternAfter[]) {
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
|
||||||
|
|
|
@ -4858,7 +4858,6 @@ private:
|
||||||
Tokenizer tokenizer(&settings0, this);
|
Tokenizer tokenizer(&settings0, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> > ;")->link());
|
|
||||||
ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> ;")->link());
|
ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> ;")->link());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue