fix #10081 (Hang: TemplateSimplifier::useDefaultArgumentValues) (#3021)

This commit is contained in:
IOBYTE 2021-01-06 17:06:50 -05:00 committed by GitHub
parent cb02628c7c
commit 503a5dd441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 17 deletions

View File

@ -985,7 +985,11 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
// template parameters with default value has syntax such as:
// x = y
// this list will contain all the '=' tokens for such arguments
std::list<Token *> eq;
struct Default {
Token *eq;
Token *end;
};
std::list<Default> eq;
// and this set the position of parameters with a default value
std::set<std::size_t> defaultedArgPos;
@ -1012,9 +1016,11 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
// end of template parameters?
if (tok->str() == ">") {
if (templateParmDepth<2)
if (templateParmDepth<2) {
if (!eq.empty())
eq.back().end = tok;
break;
else
} else
--templateParmDepth;
}
@ -1023,13 +1029,16 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
typeParameterNames[tok->strAt(1)] = templatepar - 1;
// next template parameter
if (tok->str() == "," && (1 == templateParmDepth)) // Ticket #5823: Properly count parameters
if (tok->str() == "," && (1 == templateParmDepth)) { // Ticket #5823: Properly count parameters
if (!eq.empty())
eq.back().end = tok;
++templatepar;
}
// default parameter value?
else if (Token::Match(tok, "= !!>")) {
if (defaultedArgPos.insert(templatepar).second) {
eq.push_back(tok);
eq.push_back(Default{tok, nullptr});
} else {
// Ticket #5605: Syntax error (two equal signs for the same parameter), bail out
eq.clear();
@ -1085,25 +1094,30 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
if (tok && tok->str() == ">") {
tok = tok->previous();
std::list<Token *>::const_iterator it = eq.begin();
std::list<Default>::const_iterator it = eq.begin();
for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i)
++it;
int count = 0;
while (it != eq.end()) {
int indentlevel = 0;
// check for end
if (!it->end) {
if (mSettings->debugwarnings) {
const std::list<const Token*> locationList(1, it->eq);
const ErrorMessage errmsg(locationList, &mTokenizer->list,
Severity::debug,
"noparamend",
"TemplateSimplifier couldn't find end of template parameter.",
false);
}
break;
}
if ((usedpar + count) && usedpar <= (instantiationArgs.size() + count)) {
tok->insertToken(",");
tok = tok->next();
}
const Token *from = (*it)->next();
std::stack<Token *> links;
while (from && (!links.empty() || indentlevel || !Token::Match(from, ",|>"))) {
if (from->str() == "<" &&
(from->strAt(1) == ">" || (from->previous()->isName() &&
typeParameterNames.find(from->strAt(-1)) == typeParameterNames.end())))
++indentlevel;
else if (from->str() == ">" && (links.empty() || links.top()->str() == "<" || indentlevel))
--indentlevel;
for (const Token* from = it->eq->next(); from && from != it->end; from = from->next()) {
auto entry = typeParameterNames.find(from->str());
if (entry != typeParameterNames.end() && entry->second < instantiationArgs.size()) {
for (const Token *tok1 : instantiationArgs[entry->second]) {
@ -1128,7 +1142,6 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
links.pop();
}
}
from = from->next();
}
++it;
count++;
@ -1139,7 +1152,8 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
simplifyTemplateArgs(instantiation.token()->next(), instantiationEnd);
}
for (Token * const eqtok : eq) {
for (const auto & entry : eq) {
Token *const eqtok = entry.eq;
Token *tok2;
int indentlevel = 0;
for (tok2 = eqtok->next(); tok2; tok2 = tok2->next()) {

View File

@ -208,6 +208,7 @@ private:
TEST_CASE(template163); // #9685 syntax error
TEST_CASE(template164); // #9394
TEST_CASE(template165); // #10032 syntax error
TEST_CASE(template166); // #10081 hang
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)
@ -4178,6 +4179,16 @@ private:
ASSERT_EQUALS(exp, tok(code));
}
void template166() { // #10081 hang
const char code[] = "template <typename T, size_t k = (T::s < 3) ? 0 : 3>\n"
"void foo() {}\n"
"foo<T>();";
const char exp[] = "void foo<T,(T::s<3)?0:3> ( ) ; "
"foo<T,(T::s<3)?0:3> ( ) ; "
"void foo<T,(T::s<3)?0:3> ( ) { }";
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"