From 7ebc9d1b5ff1308b701040e283febfdf1d523e3e Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Sun, 4 Aug 2019 04:24:44 -0400 Subject: [PATCH] Fix #9249 (Syntax error on valid C++) (#2062) --- lib/templatesimplifier.cpp | 48 +++++++++++++++++++++++++++++++---- lib/token.cpp | 11 +++++++- test/testsimplifytemplate.cpp | 28 ++++++++++++++++++++ 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index c20b4e981..690c91eac 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -1000,7 +1000,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) 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; // end of template parameters? @@ -1012,7 +1014,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) } // 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; // next template parameter @@ -1054,7 +1056,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) tok1 = tok1->next(); } while (tok1 && tok1 != endLink); 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(); do { instantiationArgs[index].push_back(tok1); @@ -1071,7 +1075,8 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) // count the parameters.. Token *tok = instantiation.token->next(); unsigned int usedpar = templateParameters(tok); - tok = tok->findClosingBracket(); + Token *instantiationEnd = tok->findClosingBracket(); + tok = instantiationEnd; if (tok && tok->str() == ">") { tok = tok->previous(); @@ -1088,7 +1093,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) const Token *from = (*it)->next(); std::stack links; 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; else if (from->str() == ">") --indentlevel; @@ -1123,6 +1130,8 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration) usedpar++; } } + + simplifyTemplateArgs(instantiation.token->next(), instantiationEnd); } for (Token * const eqtok : eq) { @@ -2276,6 +2285,35 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, Token *end) } else if (tok->strAt(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(); + } } } diff --git a/lib/token.cpp b/lib/token.cpp index f3a60e2fa..d34960098 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -855,6 +855,8 @@ const Token * Token::findClosingBracket() const return nullptr; const Token *closing = nullptr; + const bool templateParameter(strAt(-1) == "template"); + std::set templateParameters; unsigned int depth = 0; for (closing = this; closing != nullptr; closing = closing->next()) { @@ -864,7 +866,10 @@ const Token * Token::findClosingBracket() const return nullptr; // #6803 } else if (Token::Match(closing, "}|]|)|;")) 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; else if (closing->str() == ">") { if (--depth == 0) @@ -874,6 +879,10 @@ const Token * Token::findClosingBracket() const return closing; 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; diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index a5c4bbde3..2004495e6 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -168,6 +168,7 @@ private: TEST_CASE(template128); // #9224 TEST_CASE(template129); TEST_CASE(template130); // #9246 + TEST_CASE(template131); // #9249 TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) @@ -3101,6 +3102,33 @@ private: ASSERT_EQUALS(exp, tok(code)); } + void template131() { // #9249 + { + const char code[] = "template 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 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 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 struct S> {..}; const char code[] = "template struct C {};\n" "template struct S {a};\n"