diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index a272f3c59..e38b8c9a9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4866,7 +4866,12 @@ bool Tokenizer::simplifyConditions() bool Tokenizer::simplifyConstTernaryOp() { bool ret = false; + const Token *templateParameterEnd = 0; // The end of the current template parameter list, if any for (Token *tok = list.front(); tok; tok = tok->next()) { + if (tok->str() == "<" && TemplateSimplifier::templateParameters(tok)) + templateParameterEnd = tok->findClosingBracket(); + if (tok == templateParameterEnd) + templateParameterEnd = 0; // End of the current template parameter list if (tok->str() != "?") continue; @@ -4876,20 +4881,18 @@ bool Tokenizer::simplifyConstTernaryOp() const int offset = (tok->previous()->str() == ")") ? 2 : 1; - bool inTemplateParameter = false; if (tok->strAt(-2*offset) == "<") { if (isC() || !TemplateSimplifier::templateParameters(tok->tokAt(-2*offset))) continue; // '<' is less than; the condition is not a constant - inTemplateParameter = true; } // Find the token ":" then go to the next token - Token *semicolon = skipTernaryOp(tok); - if (!semicolon || semicolon->previous()->str() != ":" || !semicolon->next()) + Token *colon = skipTernaryOp(tok); + if (!colon || colon->previous()->str() != ":" || !colon->next()) continue; //handle the GNU extension: "x ? : y" <-> "x ? x : y" - if (semicolon->previous() == tok->next()) + if (colon->previous() == tok->next()) tok->insertToken(tok->strAt(-offset)); // go back before the condition, if possible @@ -4903,8 +4906,8 @@ bool Tokenizer::simplifyConstTernaryOp() } if (Token::Match(tok->next(), "false|0")) { - // Use code after semicolon, remove code before it. - Token::eraseTokens(tok, semicolon); + // Use code after colon, remove code before it. + Token::eraseTokens(tok, colon); tok = tok->next(); ret = true; @@ -4916,7 +4919,7 @@ bool Tokenizer::simplifyConstTernaryOp() tok->deleteNext(2); unsigned int ternaryOplevel = 0; - for (const Token *endTok = semicolon; endTok; endTok = endTok->next()) { + for (const Token *endTok = colon; endTok; endTok = endTok->next()) { if (Token::Match(endTok, "(|[|{")) { endTok = endTok->link(); } @@ -4926,10 +4929,10 @@ bool Tokenizer::simplifyConstTernaryOp() else if (Token::Match(endTok, ")|}|]|;|,|:|>")) { if (endTok->str() == ":" && ternaryOplevel) --ternaryOplevel; - else if (endTok->str() == ">" && !inTemplateParameter) + else if (endTok->str() == ">" && !templateParameterEnd) ; else { - Token::eraseTokens(semicolon->tokAt(-2), endTok); + Token::eraseTokens(colon->tokAt(-2), endTok); ret = true; break; } diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index e7c3569e6..6b69df832 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -88,6 +88,7 @@ private: TEST_CASE(template53); // #4335 - bail out for valid code TEST_CASE(template54); // #6587 - memory corruption upon valid code TEST_CASE(template55); // #6604 - simplify "const const" to "const" in template instantiations + TEST_CASE(template56); // #7117 - const ternary operator simplification as template parameter TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); @@ -1011,6 +1012,16 @@ private: "A a(0);")); } + void template56() { // #7117 + tok("template struct Foo { " + " std::array mfoo; " + "}; " + "void foo() { " + " Foo myFoo; " + "}", /*simplify=*/true, /*debugwarnings=*/true); + ASSERT_EQUALS("", errout.str()); + } + void template_enum() { const char code1[] = "template \n" "struct Unconst {\n"