Fixed #7868 (TemplateSimplifier: template specialization fails)
This commit is contained in:
parent
1fca9112d9
commit
f6fcf01cc6
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue