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;
|
std::list<ScopeInfo2> scopeInfo;
|
||||||
bool inTemplateDefinition = false;
|
bool inTemplateDefinition = false;
|
||||||
const Token *endOfTemplateDefinition = nullptr;
|
const Token *endOfTemplateDefinition = nullptr;
|
||||||
|
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
|
||||||
for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
|
for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
|
||||||
setScopeInfo(const_cast<Token *>(tok3), &scopeInfo);
|
setScopeInfo(const_cast<Token *>(tok3), &scopeInfo);
|
||||||
if (inTemplateDefinition) {
|
if (inTemplateDefinition) {
|
||||||
|
@ -987,12 +988,16 @@ void TemplateSimplifier::expandTemplate(
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace name..
|
// replace name..
|
||||||
if (Token::Match(tok3, (lastName + " !!<").c_str())) {
|
if (tok3 && tok3->str() == lastName) {
|
||||||
if (Token::Match(tok3->tokAt(-2), "> :: %name% ( )")) {
|
if (Token::Match(tok3->tokAt(-2), "> :: %name% ( )")) {
|
||||||
; // Ticket #7942: Replacing for out-of-line constructors generates invalid syntax
|
; // 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());
|
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||||
continue;
|
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;
|
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(
|
bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
TokenList& tokenlist,
|
TokenList& tokenlist,
|
||||||
ErrorLogger* errorlogger,
|
ErrorLogger* errorlogger,
|
||||||
const Settings *_settings,
|
const Settings *_settings,
|
||||||
const TokenAndName &templateDeclaration,
|
const TokenAndName &templateDeclaration,
|
||||||
|
const std::list<const Token *> &specializations,
|
||||||
const std::time_t maxtime,
|
const std::time_t maxtime,
|
||||||
std::list<TokenAndName> &templateInstantiations,
|
std::list<TokenAndName> &templateInstantiations,
|
||||||
std::set<std::string> &expandedtemplates)
|
std::set<std::string> &expandedtemplates)
|
||||||
|
@ -1407,7 +1453,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
const bool printDebug = _settings->debugwarnings;
|
const bool printDebug = _settings->debugwarnings;
|
||||||
|
|
||||||
// get the position of the template name
|
// get the position of the template name
|
||||||
int namepos = TemplateSimplifier::getTemplateNamePosition(tok);
|
const int namepos = TemplateSimplifier::getTemplateNamePosition(tok);
|
||||||
if (namepos == -1) {
|
if (namepos == -1) {
|
||||||
// debug message that we bail out..
|
// debug message that we bail out..
|
||||||
if (printDebug && errorlogger) {
|
if (printDebug && errorlogger) {
|
||||||
|
@ -1442,6 +1488,9 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
if (iter2->name != templateDeclaration.name)
|
if (iter2->name != templateDeclaration.name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!matchSpecialization(tok->tokAt(namepos), iter2->token, specializations))
|
||||||
|
continue;
|
||||||
|
|
||||||
Token * const tok2 = iter2->token;
|
Token * const tok2 = iter2->token;
|
||||||
if (errorlogger && !tokenlist.getFiles().empty())
|
if (errorlogger && !tokenlist.getFiles().empty())
|
||||||
errorlogger->reportProgress(tokenlist.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue());
|
errorlogger->reportProgress(tokenlist.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue());
|
||||||
|
@ -1676,10 +1725,22 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
//done = true;
|
//done = true;
|
||||||
std::list<TokenAndName> instantiatedTemplates;
|
std::list<TokenAndName> instantiatedTemplates;
|
||||||
for (std::list<TokenAndName>::reverse_iterator iter1 = templateDeclarations.rbegin(); iter1 != templateDeclarations.rend(); ++iter1) {
|
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,
|
bool instantiated = TemplateSimplifier::simplifyTemplateInstantiations(tokenlist,
|
||||||
errorlogger,
|
errorlogger,
|
||||||
_settings,
|
_settings,
|
||||||
*iter1,
|
*iter1,
|
||||||
|
specializations,
|
||||||
maxtime,
|
maxtime,
|
||||||
templateInstantiations,
|
templateInstantiations,
|
||||||
expandedtemplates);
|
expandedtemplates);
|
||||||
|
|
|
@ -166,6 +166,7 @@ public:
|
||||||
* @param errorlogger error logger
|
* @param errorlogger error logger
|
||||||
* @param _settings settings
|
* @param _settings settings
|
||||||
* @param templateDeclaration template declaration
|
* @param templateDeclaration template declaration
|
||||||
|
* @param specializations template specializations (list each template name token)
|
||||||
* @param maxtime time when the simplification will stop
|
* @param maxtime time when the simplification will stop
|
||||||
* @param templateInstantiations a list of template usages (not necessarily just for this template)
|
* @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.
|
* @param expandedtemplates all templates that has been expanded so far. The full names are stored.
|
||||||
|
@ -176,6 +177,7 @@ public:
|
||||||
ErrorLogger* errorlogger,
|
ErrorLogger* errorlogger,
|
||||||
const Settings *_settings,
|
const Settings *_settings,
|
||||||
const TokenAndName &templateDeclaration,
|
const TokenAndName &templateDeclaration,
|
||||||
|
const std::list<const Token *> &specializations,
|
||||||
const std::time_t maxtime,
|
const std::time_t maxtime,
|
||||||
std::list<TokenAndName> &templateInstantiations,
|
std::list<TokenAndName> &templateInstantiations,
|
||||||
std::set<std::string> &expandedtemplates);
|
std::set<std::string> &expandedtemplates);
|
||||||
|
|
|
@ -98,6 +98,8 @@ private:
|
||||||
TEST_CASE(template58); // #6021 - use after free (deleted tokens in simplifyCalculations)
|
TEST_CASE(template58); // #6021 - use after free (deleted tokens in simplifyCalculations)
|
||||||
TEST_CASE(template59); // #8051 - TemplateSimplifier::simplifyTemplateInstantiation failure
|
TEST_CASE(template59); // #8051 - TemplateSimplifier::simplifyTemplateInstantiation failure
|
||||||
TEST_CASE(template60); // handling of methods outside template definition
|
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_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
TEST_CASE(template_unhandled);
|
TEST_CASE(template_unhandled);
|
||||||
TEST_CASE(template_default_parameter);
|
TEST_CASE(template_default_parameter);
|
||||||
|
@ -1117,6 +1119,24 @@ private:
|
||||||
ASSERT_EQUALS(exp, tok(code));
|
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() {
|
void template_enum() {
|
||||||
const char code1[] = "template <class T>\n"
|
const char code1[] = "template <class T>\n"
|
||||||
"struct Unconst {\n"
|
"struct Unconst {\n"
|
||||||
|
|
Loading…
Reference in New Issue