Skip to content

Commit 503a5dd

Browse files
authored
fix #10081 (Hang: TemplateSimplifier::useDefaultArgumentValues) (#3021)
1 parent cb02628 commit 503a5dd

2 files changed

Lines changed: 42 additions & 17 deletions

File tree

lib/templatesimplifier.cpp

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,11 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
985985
// template parameters with default value has syntax such as:
986986
// x = y
987987
// this list will contain all the '=' tokens for such arguments
988-
std::list<Token *> eq;
988+
struct Default {
989+
Token *eq;
990+
Token *end;
991+
};
992+
std::list<Default> eq;
989993
// and this set the position of parameters with a default value
990994
std::set<std::size_t> defaultedArgPos;
991995

@@ -1012,9 +1016,11 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
10121016

10131017
// end of template parameters?
10141018
if (tok->str() == ">") {
1015-
if (templateParmDepth<2)
1019+
if (templateParmDepth<2) {
1020+
if (!eq.empty())
1021+
eq.back().end = tok;
10161022
break;
1017-
else
1023+
} else
10181024
--templateParmDepth;
10191025
}
10201026

@@ -1023,13 +1029,16 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
10231029
typeParameterNames[tok->strAt(1)] = templatepar - 1;
10241030

10251031
// next template parameter
1026-
if (tok->str() == "," && (1 == templateParmDepth)) // Ticket #5823: Properly count parameters
1032+
if (tok->str() == "," && (1 == templateParmDepth)) { // Ticket #5823: Properly count parameters
1033+
if (!eq.empty())
1034+
eq.back().end = tok;
10271035
++templatepar;
1036+
}
10281037

10291038
// default parameter value?
10301039
else if (Token::Match(tok, "= !!>")) {
10311040
if (defaultedArgPos.insert(templatepar).second) {
1032-
eq.push_back(tok);
1041+
eq.push_back(Default{tok, nullptr});
10331042
} else {
10341043
// Ticket #5605: Syntax error (two equal signs for the same parameter), bail out
10351044
eq.clear();
@@ -1085,25 +1094,30 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
10851094

10861095
if (tok && tok->str() == ">") {
10871096
tok = tok->previous();
1088-
std::list<Token *>::const_iterator it = eq.begin();
1097+
std::list<Default>::const_iterator it = eq.begin();
10891098
for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i)
10901099
++it;
10911100
int count = 0;
10921101
while (it != eq.end()) {
1093-
int indentlevel = 0;
1102+
// check for end
1103+
if (!it->end) {
1104+
if (mSettings->debugwarnings) {
1105+
const std::list<const Token*> locationList(1, it->eq);
1106+
const ErrorMessage errmsg(locationList, &mTokenizer->list,
1107+
Severity::debug,
1108+
"noparamend",
1109+
"TemplateSimplifier couldn't find end of template parameter.",
1110+
false);
1111+
}
1112+
break;
1113+
}
1114+
10941115
if ((usedpar + count) && usedpar <= (instantiationArgs.size() + count)) {
10951116
tok->insertToken(",");
10961117
tok = tok->next();
10971118
}
1098-
const Token *from = (*it)->next();
10991119
std::stack<Token *> links;
1100-
while (from && (!links.empty() || indentlevel || !Token::Match(from, ",|>"))) {
1101-
if (from->str() == "<" &&
1102-
(from->strAt(1) == ">" || (from->previous()->isName() &&
1103-
typeParameterNames.find(from->strAt(-1)) == typeParameterNames.end())))
1104-
++indentlevel;
1105-
else if (from->str() == ">" && (links.empty() || links.top()->str() == "<" || indentlevel))
1106-
--indentlevel;
1120+
for (const Token* from = it->eq->next(); from && from != it->end; from = from->next()) {
11071121
auto entry = typeParameterNames.find(from->str());
11081122
if (entry != typeParameterNames.end() && entry->second < instantiationArgs.size()) {
11091123
for (const Token *tok1 : instantiationArgs[entry->second]) {
@@ -1128,7 +1142,6 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
11281142
links.pop();
11291143
}
11301144
}
1131-
from = from->next();
11321145
}
11331146
++it;
11341147
count++;
@@ -1139,7 +1152,8 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
11391152
simplifyTemplateArgs(instantiation.token()->next(), instantiationEnd);
11401153
}
11411154

1142-
for (Token * const eqtok : eq) {
1155+
for (const auto & entry : eq) {
1156+
Token *const eqtok = entry.eq;
11431157
Token *tok2;
11441158
int indentlevel = 0;
11451159
for (tok2 = eqtok->next(); tok2; tok2 = tok2->next()) {

test/testsimplifytemplate.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ class TestSimplifyTemplate : public TestFixture {
208208
TEST_CASE(template163); // #9685 syntax error
209209
TEST_CASE(template164); // #9394
210210
TEST_CASE(template165); // #10032 syntax error
211+
TEST_CASE(template166); // #10081 hang
211212
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
212213
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
213214
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
@@ -4178,6 +4179,16 @@ class TestSimplifyTemplate : public TestFixture {
41784179
ASSERT_EQUALS(exp, tok(code));
41794180
}
41804181

4182+
void template166() { // #10081 hang
4183+
const char code[] = "template <typename T, size_t k = (T::s < 3) ? 0 : 3>\n"
4184+
"void foo() {}\n"
4185+
"foo<T>();";
4186+
const char exp[] = "void foo<T,(T::s<3)?0:3> ( ) ; "
4187+
"foo<T,(T::s<3)?0:3> ( ) ; "
4188+
"void foo<T,(T::s<3)?0:3> ( ) { }";
4189+
ASSERT_EQUALS(exp, tok(code));
4190+
}
4191+
41814192
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
41824193
const char code[] = "template <typename T> struct C {};\n"
41834194
"template <typename T> struct S {a};\n"

0 commit comments

Comments
 (0)