Fixed #7868 (TemplateSimplifier: template specialization fails)

This commit is contained in:
Daniel Marjamäki 2017-12-30 22:14:48 +01:00
parent 1fca9112d9
commit f6fcf01cc6
3 changed files with 86 additions and 3 deletions

View File

@ -906,6 +906,7 @@ void TemplateSimplifier::expandTemplate(
std::list<ScopeInfo2> scopeInfo;
bool inTemplateDefinition = false;
const Token *endOfTemplateDefinition = nullptr;
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
setScopeInfo(const_cast<Token *>(tok3), &scopeInfo);
if (inTemplateDefinition) {
@ -987,12 +988,16 @@ void TemplateSimplifier::expandTemplate(
}
// replace name..
if (Token::Match(tok3, (lastName + " !!<").c_str())) {
if (tok3 && tok3->str() == lastName) {
if (Token::Match(tok3->tokAt(-2), "> :: %name% ( )")) {
; // Ticket #7942: Replacing for out-of-line constructors generates invalid syntax
} else {
} else if (!Token::simpleMatch(tok3->next(), "<")) {
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
continue;
} else if (tok3 == templateDeclarationNameToken) {
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
tok3 = tok3->next()->findClosingBracket();
continue;
}
}
@ -1383,11 +1388,52 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
return tok;
}
static bool matchSpecialization(const Token *templateDeclarationNameToken, const Token *templateInstantiationNameToken, const std::list<const Token *> & specializations)
{
// Is there a matching specialization?
for (std::list<const Token *>::const_iterator it = specializations.begin(); it != specializations.end(); ++it) {
if (!Token::Match(*it, "%name% <"))
continue;
const Token *startToken = (*it);
while (startToken->previous() && !Token::Match(startToken->previous(), "[;{}]"))
startToken = startToken->previous();
if (!Token::Match(startToken, "template <"))
continue;
std::vector<const Token *> templateParameters;
TemplateSimplifier::getTemplateParametersInDeclaration(startToken->tokAt(2), templateParameters);
const Token *instToken = templateInstantiationNameToken->tokAt(2);
const Token *declToken = (*it)->tokAt(2);
const Token * const endToken = (*it)->next()->findClosingBracket();
while (declToken != endToken) {
if (declToken->str() != instToken->str()) {
int nr = 0;
while (nr < templateParameters.size() && templateParameters[nr]->str() != declToken->str())
++nr;
if (nr == templateParameters.size())
break;
}
declToken = declToken->next();
instToken = instToken->next();
}
if (declToken == endToken && instToken->str() == ">") {
// specialization matches.
return templateDeclarationNameToken == *it;
}
}
// No specialization matches. Return true if the declaration is not a specialization.
return Token::Match(templateDeclarationNameToken, "%name% !!<");
}
bool TemplateSimplifier::simplifyTemplateInstantiations(
TokenList& tokenlist,
ErrorLogger* errorlogger,
const Settings *_settings,
const TokenAndName &templateDeclaration,
const std::list<const Token *> &specializations,
const std::time_t maxtime,
std::list<TokenAndName> &templateInstantiations,
std::set<std::string> &expandedtemplates)
@ -1407,7 +1453,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
const bool printDebug = _settings->debugwarnings;
// get the position of the template name
int namepos = TemplateSimplifier::getTemplateNamePosition(tok);
const int namepos = TemplateSimplifier::getTemplateNamePosition(tok);
if (namepos == -1) {
// debug message that we bail out..
if (printDebug && errorlogger) {
@ -1442,6 +1488,9 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
if (iter2->name != templateDeclaration.name)
continue;
if (!matchSpecialization(tok->tokAt(namepos), iter2->token, specializations))
continue;
Token * const tok2 = iter2->token;
if (errorlogger && !tokenlist.getFiles().empty())
errorlogger->reportProgress(tokenlist.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue());
@ -1676,10 +1725,22 @@ void TemplateSimplifier::simplifyTemplates(
//done = true;
std::list<TokenAndName> instantiatedTemplates;
for (std::list<TokenAndName>::reverse_iterator iter1 = templateDeclarations.rbegin(); iter1 != templateDeclarations.rend(); ++iter1) {
// get specializations..
std::list<const Token *> specializations;
for (std::list<TokenAndName>::const_iterator iter2 = templateDeclarations.begin(); iter2 != templateDeclarations.end(); ++iter2) {
if (iter1->name == iter2->name) {
const Token *tok = iter2->token->next()->findClosingBracket();
int namepos = getTemplateNamePosition(tok);
if (namepos > 0)
specializations.push_back(tok->tokAt(namepos));
}
}
bool instantiated = TemplateSimplifier::simplifyTemplateInstantiations(tokenlist,
errorlogger,
_settings,
*iter1,
specializations,
maxtime,
templateInstantiations,
expandedtemplates);

View File

@ -166,6 +166,7 @@ public:
* @param errorlogger error logger
* @param _settings settings
* @param templateDeclaration template declaration
* @param specializations template specializations (list each template name token)
* @param maxtime time when the simplification will stop
* @param templateInstantiations a list of template usages (not necessarily just for this template)
* @param expandedtemplates all templates that has been expanded so far. The full names are stored.
@ -176,6 +177,7 @@ public:
ErrorLogger* errorlogger,
const Settings *_settings,
const TokenAndName &templateDeclaration,
const std::list<const Token *> &specializations,
const std::time_t maxtime,
std::list<TokenAndName> &templateInstantiations,
std::set<std::string> &expandedtemplates);

View File

@ -98,6 +98,8 @@ private:
TEST_CASE(template58); // #6021 - use after free (deleted tokens in simplifyCalculations)
TEST_CASE(template59); // #8051 - TemplateSimplifier::simplifyTemplateInstantiation failure
TEST_CASE(template60); // handling of methods outside template definition
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)
TEST_CASE(template_unhandled);
TEST_CASE(template_default_parameter);
@ -1117,6 +1119,24 @@ private:
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"
"template <typename T> struct S<C<T>> {b};\n"
"S<int> s;";
const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S < C < T > > { b } ; S<int> s ; struct S<int> { a } ;";
ASSERT_EQUALS(exp, tok(code));
}
void template_specialization_2() { // #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"
"template <typename T> struct S<C<T>> {b};\n"
"S<C<int>> s;";
const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S { a } ; S<C<int>> s ; struct S<C<int>> { b } ;";
ASSERT_EQUALS(exp, tok(code));
}
void template_enum() {
const char code1[] = "template <class T>\n"
"struct Unconst {\n"