Ticket #7117: Properly detect if a const ternary operator is in a template parameter list.
This commit is contained in:
parent
583b340034
commit
3c10b25b3e
|
@ -4866,7 +4866,12 @@ bool Tokenizer::simplifyConditions()
|
||||||
bool Tokenizer::simplifyConstTernaryOp()
|
bool Tokenizer::simplifyConstTernaryOp()
|
||||||
{
|
{
|
||||||
bool ret = false;
|
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()) {
|
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() != "?")
|
if (tok->str() != "?")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -4876,20 +4881,18 @@ bool Tokenizer::simplifyConstTernaryOp()
|
||||||
|
|
||||||
const int offset = (tok->previous()->str() == ")") ? 2 : 1;
|
const int offset = (tok->previous()->str() == ")") ? 2 : 1;
|
||||||
|
|
||||||
bool inTemplateParameter = false;
|
|
||||||
if (tok->strAt(-2*offset) == "<") {
|
if (tok->strAt(-2*offset) == "<") {
|
||||||
if (isC() || !TemplateSimplifier::templateParameters(tok->tokAt(-2*offset)))
|
if (isC() || !TemplateSimplifier::templateParameters(tok->tokAt(-2*offset)))
|
||||||
continue; // '<' is less than; the condition is not a constant
|
continue; // '<' is less than; the condition is not a constant
|
||||||
inTemplateParameter = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the token ":" then go to the next token
|
// Find the token ":" then go to the next token
|
||||||
Token *semicolon = skipTernaryOp(tok);
|
Token *colon = skipTernaryOp(tok);
|
||||||
if (!semicolon || semicolon->previous()->str() != ":" || !semicolon->next())
|
if (!colon || colon->previous()->str() != ":" || !colon->next())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//handle the GNU extension: "x ? : y" <-> "x ? x : y"
|
//handle the GNU extension: "x ? : y" <-> "x ? x : y"
|
||||||
if (semicolon->previous() == tok->next())
|
if (colon->previous() == tok->next())
|
||||||
tok->insertToken(tok->strAt(-offset));
|
tok->insertToken(tok->strAt(-offset));
|
||||||
|
|
||||||
// go back before the condition, if possible
|
// go back before the condition, if possible
|
||||||
|
@ -4903,8 +4906,8 @@ bool Tokenizer::simplifyConstTernaryOp()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(tok->next(), "false|0")) {
|
if (Token::Match(tok->next(), "false|0")) {
|
||||||
// Use code after semicolon, remove code before it.
|
// Use code after colon, remove code before it.
|
||||||
Token::eraseTokens(tok, semicolon);
|
Token::eraseTokens(tok, colon);
|
||||||
|
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
ret = true;
|
ret = true;
|
||||||
|
@ -4916,7 +4919,7 @@ bool Tokenizer::simplifyConstTernaryOp()
|
||||||
tok->deleteNext(2);
|
tok->deleteNext(2);
|
||||||
|
|
||||||
unsigned int ternaryOplevel = 0;
|
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, "(|[|{")) {
|
if (Token::Match(endTok, "(|[|{")) {
|
||||||
endTok = endTok->link();
|
endTok = endTok->link();
|
||||||
}
|
}
|
||||||
|
@ -4926,10 +4929,10 @@ bool Tokenizer::simplifyConstTernaryOp()
|
||||||
else if (Token::Match(endTok, ")|}|]|;|,|:|>")) {
|
else if (Token::Match(endTok, ")|}|]|;|,|:|>")) {
|
||||||
if (endTok->str() == ":" && ternaryOplevel)
|
if (endTok->str() == ":" && ternaryOplevel)
|
||||||
--ternaryOplevel;
|
--ternaryOplevel;
|
||||||
else if (endTok->str() == ">" && !inTemplateParameter)
|
else if (endTok->str() == ">" && !templateParameterEnd)
|
||||||
;
|
;
|
||||||
else {
|
else {
|
||||||
Token::eraseTokens(semicolon->tokAt(-2), endTok);
|
Token::eraseTokens(colon->tokAt(-2), endTok);
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ private:
|
||||||
TEST_CASE(template53); // #4335 - bail out for valid code
|
TEST_CASE(template53); // #4335 - bail out for valid code
|
||||||
TEST_CASE(template54); // #6587 - memory corruption upon 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(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_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
TEST_CASE(template_unhandled);
|
TEST_CASE(template_unhandled);
|
||||||
TEST_CASE(template_default_parameter);
|
TEST_CASE(template_default_parameter);
|
||||||
|
@ -1011,6 +1012,16 @@ private:
|
||||||
"A<int> a(0);"));
|
"A<int> a(0);"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template56() { // #7117
|
||||||
|
tok("template<bool B> struct Foo { "
|
||||||
|
" std::array<int, B ? 1 : 2> mfoo; "
|
||||||
|
"}; "
|
||||||
|
"void foo() { "
|
||||||
|
" Foo<true> myFoo; "
|
||||||
|
"}", /*simplify=*/true, /*debugwarnings=*/true);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void template_enum() {
|
void template_enum() {
|
||||||
const char code1[] = "template <class T>\n"
|
const char code1[] = "template <class T>\n"
|
||||||
"struct Unconst {\n"
|
"struct Unconst {\n"
|
||||||
|
|
Loading…
Reference in New Issue