Fixed #4272 and #6237 (Crash from running out of memory with many templates)

This commit is contained in:
Frank Zingsheim 2014-11-01 22:07:24 +01:00 committed by PKEuS
parent fe468ac142
commit 0e4c508d7b
3 changed files with 80 additions and 5 deletions

View File

@ -721,7 +721,19 @@ void TemplateSimplifier::expandTemplate(
std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<Token *> &templateInstantiations)
{
bool inTemplateDefinition=false;
std::vector<const Token *> localTypeParametersInDeclaration;
for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
if (tok3->str()=="template") {
if (tok3->next() && tok3->next()->str()=="<") {
TemplateParametersInDeclaration(tok3->tokAt(2), localTypeParametersInDeclaration);
if (localTypeParametersInDeclaration.size() != typeParametersInDeclaration.size())
inTemplateDefinition = false; // Partial specialization
else
inTemplateDefinition = true;
} else
inTemplateDefinition = false; // Only template instantiation
}
if (Token::Match(tok3, "{|(|["))
tok3 = tok3->link();
@ -731,7 +743,8 @@ void TemplateSimplifier::expandTemplate(
}
// member function implemented outside class definition
else if (TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %var% (")) {
else if (inTemplateDefinition &&
TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %var% (")) {
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
while (tok3 && tok3->str() != "::")
tok3 = tok3->next();
@ -1150,6 +1163,17 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
return ret;
}
const Token * TemplateSimplifier::TemplateParametersInDeclaration(
const Token * tok,
std::vector<const Token *> & typeParametersInDeclaration)
{
typeParametersInDeclaration.clear();
for (; tok && tok->str() != ">"; tok = tok->next()) {
if (Token::Match(tok, "%var% ,|>"))
typeParametersInDeclaration.push_back(tok);
}
return tok;
}
bool TemplateSimplifier::simplifyTemplateInstantiations(
TokenList& tokenlist,
@ -1165,10 +1189,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
// Contains tokens such as "T"
std::vector<const Token *> typeParametersInDeclaration;
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) {
if (Token::Match(tok, "%var% ,|>"))
typeParametersInDeclaration.push_back(tok);
}
tok = TemplateParametersInDeclaration(tok->tokAt(2), typeParametersInDeclaration);
// bail out if the end of the file was reached
if (!tok)

View File

@ -117,6 +117,19 @@ public:
std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<Token *> &templateInstantiations);
/**
* @brief TemplateParametersInDeclaration
* @param tok template < typename T, typename S >
* ^ tok
* @param typeParametersInDeclaration template < typename T, typename S >
* ^ [0] ^ [1]
* @return template < typename T, typename S >
* ^ return
*/
static const Token * TemplateParametersInDeclaration(
const Token * tok,
std::vector<const Token *> & typeParametersInDeclaration);
/**
* Simplify templates : expand all instantiations for a template
* @todo It seems that inner templates should be instantiated recursively

View File

@ -83,6 +83,8 @@ private:
TEST_CASE(template46); // #5816 - syntax error reported for valid code
TEST_CASE(template47); // #6023 - syntax error reported for valid code
TEST_CASE(template48); // #6134 - 100% CPU upon invalid code
TEST_CASE(template49); // #6237 - template instantiation
TEST_CASE(template50); // #4272 - simple partial specialization
TEST_CASE(template_unhandled);
TEST_CASE(template_default_parameter);
TEST_CASE(template_default_type);
@ -878,6 +880,45 @@ private:
ASSERT_EQUALS("", errout.str());
}
void template49() { // #6237
const char code[] = "template <classname T> class Fred { void f(); void g(); };\n"
"template <classname T> void Fred<T>::f() { }\n"
"template <classname T> void Fred<T>::g() { }\n"
"template void Fred<float>::f();\n"
"template void Fred<int>::g();\n";
const std::string expected("template < classname T > void Fred<T> :: f ( ) { } "
"template < classname T > void Fred<T> :: g ( ) { } "
"template void Fred<float> :: f ( ) ; "
"template void Fred<int> :: g ( ) ; "
"class Fred<T> { void f ( ) ; void g ( ) ; } ; "
"Fred<T> :: f ( ) { } "
"Fred<T> :: g ( ) { } "
"class Fred<float> { void f ( ) ; void g ( ) ; } ; "
"class Fred<int> { void f ( ) ; void g ( ) ; } ;");
ASSERT_EQUALS(expected, tok(code));
}
void template50() { // #4272
const char code[] = "template <classname T> class Fred { void f(); };\n"
"template <classname T> void Fred<T>::f() { }\n"
"template<> void Fred<float>::f() { }\n"
"template<> void Fred<int>::g() { }\n";
const std::string expected("template < classname T > void Fred<T> :: f ( ) { } "
"template < > void Fred<float> :: f ( ) { } "
"template < > void Fred<int> :: g ( ) { } "
"class Fred<T> { void f ( ) ; } ; "
"Fred<T> :: f ( ) { } "
"class Fred<float> { void f ( ) ; } ; "
"class Fred<int> { void f ( ) ; } ;");
ASSERT_EQUALS(expected, tok(code));
}
void template_default_parameter() {
{
const char code[] = "template <class T, int n=3>\n"