Fix #9249 (Syntax error on valid C++) (#2062)

This commit is contained in:
IOBYTE 2019-08-04 04:24:44 -04:00 committed by Daniel Marjamäki
parent 510748134f
commit 7ebc9d1b5f
3 changed files with 81 additions and 6 deletions

View File

@ -1000,7 +1000,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
continue; continue;
} }
if (tok->str() == "<" && (tok->strAt(1) == ">" || templateParameters(tok))) if (tok->str() == "<" &&
(tok->strAt(1) == ">" || (tok->previous()->isName() &&
typeParameterNames.find(tok->strAt(-1)) == typeParameterNames.end())))
++templateParmDepth; ++templateParmDepth;
// end of template parameters? // end of template parameters?
@ -1012,7 +1014,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
} }
// map type parameter name to index // map type parameter name to index
if (Token::Match(tok, "typename|class %name% ,|>")) if (Token::Match(tok, "typename|class|%type% %name% ,|>"))
typeParameterNames[tok->strAt(1)] = templatepar - 1; typeParameterNames[tok->strAt(1)] = templatepar - 1;
// next template parameter // next template parameter
@ -1054,7 +1056,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
tok1 = tok1->next(); tok1 = tok1->next();
} while (tok1 && tok1 != endLink); } while (tok1 && tok1 != endLink);
instantiationArgs[index].push_back(tok1); instantiationArgs[index].push_back(tok1);
} else if (tok1->str() == "<" && (tok1->strAt(1) == ">" || templateParameters(tok1))) { } else if (tok1->str() == "<" &&
(tok1->strAt(1) == ">" || (tok1->previous()->isName() &&
typeParameterNames.find(tok1->strAt(-1)) == typeParameterNames.end()))) {
const Token *endLink = tok1->findClosingBracket(); const Token *endLink = tok1->findClosingBracket();
do { do {
instantiationArgs[index].push_back(tok1); instantiationArgs[index].push_back(tok1);
@ -1071,7 +1075,8 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
// count the parameters.. // count the parameters..
Token *tok = instantiation.token->next(); Token *tok = instantiation.token->next();
unsigned int usedpar = templateParameters(tok); unsigned int usedpar = templateParameters(tok);
tok = tok->findClosingBracket(); Token *instantiationEnd = tok->findClosingBracket();
tok = instantiationEnd;
if (tok && tok->str() == ">") { if (tok && tok->str() == ">") {
tok = tok->previous(); tok = tok->previous();
@ -1088,7 +1093,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
const Token *from = (*it)->next(); const Token *from = (*it)->next();
std::stack<Token *> links; std::stack<Token *> links;
while (from && (!links.empty() || indentlevel || !Token::Match(from, ",|>"))) { while (from && (!links.empty() || indentlevel || !Token::Match(from, ",|>"))) {
if (from->str() == "<" && (from->strAt(1) == ">" || templateParameters(from))) if (from->str() == "<" &&
(from->strAt(1) == ">" || (from->previous()->isName() &&
typeParameterNames.find(from->strAt(-1)) == typeParameterNames.end())))
++indentlevel; ++indentlevel;
else if (from->str() == ">") else if (from->str() == ">")
--indentlevel; --indentlevel;
@ -1123,6 +1130,8 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
usedpar++; usedpar++;
} }
} }
simplifyTemplateArgs(instantiation.token->next(), instantiationEnd);
} }
for (Token * const eqtok : eq) { for (Token * const eqtok : eq) {
@ -2276,6 +2285,35 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, Token *end)
} else if (tok->strAt(1) == "(") { } else if (tok->strAt(1) == "(") {
tok = tok->linkAt(1); tok = tok->linkAt(1);
} }
} else if (Token::Match(tok, "%num% %comp% %num%") &&
MathLib::isInt(tok->str()) &&
MathLib::isInt(tok->strAt(2))) {
if ((Token::Match(tok->previous(), "(|&&|%oror%|,") || tok->previous() == start) &&
(Token::Match(tok->tokAt(3), ")|&&|%oror%|?") || tok->tokAt(3) == end)) {
const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
const std::string &cmp(tok->next()->str());
const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2)));
std::string result;
if (cmp == "==")
result = (op1 == op2) ? "true" : "false";
else if (cmp == "!=")
result = (op1 != op2) ? "true" : "false";
else if (cmp == "<=")
result = (op1 <= op2) ? "true" : "false";
else if (cmp == ">=")
result = (op1 >= op2) ? "true" : "false";
else if (cmp == "<")
result = (op1 < op2) ? "true" : "false";
else
result = (op1 > op2) ? "true" : "false";
tok->str(result);
tok->deleteNext(2);
again = true;
tok = tok->previous();
}
} }
} }

View File

@ -855,6 +855,8 @@ const Token * Token::findClosingBracket() const
return nullptr; return nullptr;
const Token *closing = nullptr; const Token *closing = nullptr;
const bool templateParameter(strAt(-1) == "template");
std::set<std::string> templateParameters;
unsigned int depth = 0; unsigned int depth = 0;
for (closing = this; closing != nullptr; closing = closing->next()) { for (closing = this; closing != nullptr; closing = closing->next()) {
@ -864,7 +866,10 @@ const Token * Token::findClosingBracket() const
return nullptr; // #6803 return nullptr; // #6803
} else if (Token::Match(closing, "}|]|)|;")) } else if (Token::Match(closing, "}|]|)|;"))
return nullptr; return nullptr;
else if (closing->str() == "<") // we can make some guesses for template parameters
else if (closing->str() == "<" &&
(!templateParameter || (closing->previous() && closing->previous()->isName() &&
templateParameters.find(closing->strAt(-1)) == templateParameters.end())))
++depth; ++depth;
else if (closing->str() == ">") { else if (closing->str() == ">") {
if (--depth == 0) if (--depth == 0)
@ -874,6 +879,10 @@ const Token * Token::findClosingBracket() const
return closing; return closing;
depth -= 2; depth -= 2;
} }
// save named template parameter
else if (templateParameter && depth == 1 && closing->str() == "," &&
closing->previous()->isName() && !Match(closing->previous(), "class|typename|."))
templateParameters.insert(closing->strAt(-1));
} }
return closing; return closing;

View File

@ -168,6 +168,7 @@ private:
TEST_CASE(template128); // #9224 TEST_CASE(template128); // #9224
TEST_CASE(template129); TEST_CASE(template129);
TEST_CASE(template130); // #9246 TEST_CASE(template130); // #9246
TEST_CASE(template131); // #9249
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..}; 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_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)
@ -3101,6 +3102,33 @@ private:
ASSERT_EQUALS(exp, tok(code)); ASSERT_EQUALS(exp, tok(code));
} }
void template131() { // #9249
{
const char code[] = "template <long a, bool = 0 == a> struct b {};\n"
"b<1> b1;";
const char exp[] = "struct b<1,false> ; "
"b<1,false> b1 ; "
"struct b<1,false> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
{
const char code[] = "template <long a, bool = a < 0> struct b {};\n"
"b<1> b1;";
const char exp[] = "struct b<1,false> ; "
"b<1,false> b1 ; "
"struct b<1,false> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
{
const char code[] = "template <long a, bool = 0 < a> struct b {};\n"
"b<1> b1;";
const char exp[] = "struct b<1,true> ; "
"b<1,true> b1 ; "
"struct b<1,true> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
}
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..}; void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
const char code[] = "template <typename T> struct C {};\n" const char code[] = "template <typename T> struct C {};\n"
"template <typename T> struct S {a};\n" "template <typename T> struct S {a};\n"