Fixed #9021 (template simplifier: crash in simplifyCalculations) (#1757)

This commit is contained in:
IOBYTE 2019-03-25 09:56:51 -04:00 committed by Daniel Marjamäki
parent 5036cb9ca6
commit 10fcf731d9
2 changed files with 154 additions and 38 deletions

View File

@ -354,6 +354,13 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
tok = tok->link();
if (tok)
tok = tok->next();
if (tok->str() == ">" && level == 0)
return numberOfParameters;
else if (tok->str() == "," && level == 0) {
++numberOfParameters;
tok = tok->next();
}
continue;
}
// skip std::
@ -1930,12 +1937,14 @@ static Token *skipTernaryOp(Token *tok, Token *backToken)
void TemplateSimplifier::simplifyTemplateArgs(Token *start, Token *end)
{
// start could be erased so use the token before start if available
Token * first = (start && start->previous()) ? start->previous() : mTokenList.front();
bool again = true;
while (again) {
again = false;
for (Token *tok = start; tok && tok != end; tok = tok->next()) {
for (Token *tok = first->next(); tok && tok != end; tok = tok->next()) {
if (tok->str() == "sizeof") {
// sizeof('x')
if (Token::Match(tok->next(), "( %char% )")) {
@ -1980,11 +1989,11 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, Token *end)
}
}
if (simplifyCalculations(start, end))
if (simplifyCalculations(first->next(), end))
again = true;
for (Token *tok = start; tok && tok != end; tok = tok->next()) {
if (tok->str() == "?" && tok->previous()->isNumber()) {
for (Token *tok = first->next(); tok && tok != end; tok = tok->next()) {
if (tok->str() == "?" && (tok->previous()->isNumber() || tok->previous()->isBoolean())) {
const int offset = (tok->previous()->str() == ")") ? 2 : 1;
// Find the token ":" then go to the next token
@ -2043,24 +2052,60 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, Token *end)
}
}
for (Token *tok = start; tok && tok != end; tok = tok->next()) {
if (Token::Match(tok, "( %num% )") && !Token::Match(tok->previous(), "%name%")) {
for (Token *tok = first->next(); tok && tok != end; tok = tok->next()) {
if (Token::Match(tok, "( %num%|%bool% )") &&
(tok->previous() && !Token::Match(tok->previous(), "%name%"))) {
tok->deleteThis();
tok->deleteNext();
again = true;
}
}
}
}
static bool validTokenStart(bool bounded, const Token *tok, const Token *frontToken, int offset)
{
if (!bounded)
return true;
if (frontToken)
frontToken = frontToken->previous();
while (tok && offset <= 0) {
if (tok == frontToken)
return false;
++offset;
tok = tok->previous();
}
return tok && offset > 0;
}
static bool validTokenEnd(bool bounded, const Token *tok, const Token *backToken, int offset)
{
if (!bounded)
return true;
while (tok && offset >= 0) {
if (tok == backToken)
return false;
--offset;
tok = tok->next();
}
return tok && offset < 0;
}
// TODO: This is not the correct class for simplifyCalculations(), so it
// should be moved away.
bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToken)
{
bool ret = false;
const bool bounded = frontToken || backToken;
if (!frontToken) {
frontToken = mTokenList.front();
}
for (Token *tok = frontToken; tok != backToken; tok = tok->next()) {
for (Token *tok = frontToken; tok && tok != backToken; tok = tok->next()) {
// Remove parentheses around variable..
// keep parentheses here: dynamic_cast<Fred *>(p);
// keep parentheses here: A operator * (int);
@ -2069,8 +2114,11 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
// keep parentheses here: operator new [] (size_t);
// keep parentheses here: Functor()(a ... )
// keep parentheses here: ) ( var ) ;
if ((Token::Match(tok->next(), "( %name% ) ;|)|,|]") ||
(Token::Match(tok->next(), "( %name% ) %cop%") && (tok->tokAt(2)->varId()>0 || !Token::Match(tok->tokAt(4), "[*&+-~]")))) &&
if (validTokenEnd(bounded, tok, backToken, 4) &&
(Token::Match(tok->next(), "( %name% ) ;|)|,|]") ||
(Token::Match(tok->next(), "( %name% ) %cop%") &&
(tok->tokAt(2)->varId()>0 ||
!Token::Match(tok->tokAt(4), "[*&+-~]")))) &&
!tok->isName() &&
tok->str() != ">" &&
tok->str() != ")" &&
@ -2081,23 +2129,28 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
ret = true;
}
if (Token::Match(tok->previous(), "(|&&|%oror% %char% %comp% %num% &&|%oror%|)")) {
if (validTokenEnd(bounded, tok, backToken, 3) &&
Token::Match(tok->previous(), "(|&&|%oror% %char% %comp% %num% &&|%oror%|)")) {
tok->str(MathLib::toString(MathLib::toLongNumber(tok->str())));
}
if (tok->isNumber()) {
if (simplifyNumericCalculations(tok)) {
if (tok && tok->isNumber()) {
if (validTokenEnd(bounded, tok, backToken, 2) &&
simplifyNumericCalculations(tok)) {
ret = true;
Token *prev = tok->tokAt(-2);
while (prev && simplifyNumericCalculations(prev)) {
while (validTokenStart(bounded, tok, frontToken, -2) &&
prev && simplifyNumericCalculations(prev)) {
tok = prev;
prev = prev->tokAt(-2);
}
}
// Remove redundant conditions (0&&x) (1||x)
if (Token::Match(tok->previous(), "[(=,] 0 &&") ||
Token::Match(tok->previous(), "[(=,] 1 %oror%")) {
if (validTokenStart(bounded, tok, frontToken, -1) &&
validTokenEnd(bounded, tok, backToken, 1) &&
(Token::Match(tok->previous(), "[(=,] 0 &&") ||
Token::Match(tok->previous(), "[(=,] 1 %oror%"))) {
unsigned int par = 0;
const Token *tok2 = tok;
const bool andAnd = (tok->next()->str() == "&&");
@ -2118,9 +2171,10 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
continue;
}
if (tok->str() == "0") {
if ((Token::Match(tok->previous(), "[+-] 0 %cop%|;") && isLowerThanMulDiv(tok->next())) ||
(Token::Match(tok->previous(), "%or% 0 %cop%|;") && isLowerThanXor(tok->next()))) {
if (tok->str() == "0" && validTokenStart(bounded, tok, frontToken, -1)) {
if (validTokenEnd(bounded, tok, backToken, 1) &&
((Token::Match(tok->previous(), "[+-] 0 %cop%|;") && isLowerThanMulDiv(tok->next())) ||
(Token::Match(tok->previous(), "%or% 0 %cop%|;") && isLowerThanXor(tok->next())))) {
tok = tok->previous();
if (Token::Match(tok->tokAt(-4), "[;{}] %name% = %name% [+-|] 0 ;") &&
tok->strAt(-3) == tok->previous()->str()) {
@ -2131,22 +2185,26 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
tok->deleteNext(2);
}
ret = true;
} else if (Token::Match(tok->previous(), "[=([,] 0 [+|]") ||
Token::Match(tok->previous(), "return|case 0 [+|]")) {
} else if (validTokenEnd(bounded, tok, backToken, 1) &&
(Token::Match(tok->previous(), "[=([,] 0 [+|]") ||
Token::Match(tok->previous(), "return|case 0 [+|]"))) {
tok = tok->previous();
tok->deleteNext(2);
ret = true;
} else if (Token::Match(tok->previous(), "[=[(,] 0 * %name%|%num% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "[=[(,] 0 * (") ||
Token::Match(tok->previous(), "return|case 0 *|&& %name%|%num% ,|:|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 0 *|&& (")) {
} else if ((((Token::Match(tok->previous(), "[=[(,] 0 * %name%|%num% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 0 *|&& %name%|%num% ,|:|;|=|%cop%")) &&
validTokenEnd(bounded, tok, backToken, 3)) ||
(((Token::Match(tok->previous(), "[=[(,] 0 * (") ||
Token::Match(tok->previous(), "return|case 0 *|&& (")) &&
validTokenEnd(bounded, tok, backToken, 2))))) {
tok->deleteNext();
if (tok->next()->str() == "(")
eraseTokens(tok, tok->next()->link());
tok->deleteNext();
ret = true;
} else if (Token::Match(tok->previous(), "[=[(,] 0 && *|& %any% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 0 && *|& %any% ,|:|;|=|%cop%")) {
} else if (validTokenEnd(bounded, tok, backToken, 4) &&
(Token::Match(tok->previous(), "[=[(,] 0 && *|& %any% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 0 && *|& %any% ,|:|;|=|%cop%"))) {
tok->deleteNext();
tok->deleteNext();
if (tok->next()->str() == "(")
@ -2156,16 +2214,18 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
}
}
if (tok->str() == "1") {
if (Token::Match(tok->previous(), "[=[(,] 1 %oror% %any% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 1 %oror% %any% ,|:|;|=|%cop%")) {
if (tok->str() == "1" && validTokenStart(bounded, tok, frontToken, -1)) {
if (validTokenEnd(bounded, tok, backToken, 3) &&
(Token::Match(tok->previous(), "[=[(,] 1 %oror% %any% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 1 %oror% %any% ,|:|;|=|%cop%"))) {
tok->deleteNext();
if (tok->next()->str() == "(")
eraseTokens(tok, tok->next()->link());
tok->deleteNext();
ret = true;
} else if (Token::Match(tok->previous(), "[=[(,] 1 %oror% *|& %any% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 1 %oror% *|& %any% ,|:|;|=|%cop%")) {
} else if (validTokenEnd(bounded, tok, backToken, 4) &&
(Token::Match(tok->previous(), "[=[(,] 1 %oror% *|& %any% ,|]|)|;|=|%cop%") ||
Token::Match(tok->previous(), "return|case 1 %oror% *|& %any% ,|:|;|=|%cop%"))) {
tok->deleteNext();
tok->deleteNext();
if (tok->next()->str() == "(")
@ -2175,7 +2235,10 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
}
}
if (Token::Match(tok->tokAt(-2), "%any% * 1") || Token::Match(tok->previous(), "%any% 1 *")) {
if ((Token::Match(tok->tokAt(-2), "%any% * 1") &&
validTokenStart(bounded, tok, frontToken, -2)) ||
(Token::Match(tok->previous(), "%any% 1 *") &&
validTokenStart(bounded, tok, frontToken, -1))) {
tok = tok->previous();
if (tok->str() == "*")
tok = tok->previous();
@ -2184,15 +2247,19 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
}
// Remove parentheses around number..
if (Token::Match(tok->tokAt(-2), "%op%|< ( %num% )") && tok->strAt(-2) != ">") {
if (validTokenStart(bounded, tok, frontToken, -2) &&
Token::Match(tok->tokAt(-2), "%op%|< ( %num% )") &&
tok->strAt(-2) != ">") {
tok = tok->previous();
tok->deleteThis();
tok->deleteNext();
ret = true;
}
if (Token::Match(tok->previous(), "( 0 [|+]") ||
Token::Match(tok->previous(), "[|+-] 0 )")) {
if (validTokenStart(bounded, tok, frontToken, -1) &&
validTokenEnd(bounded, tok, backToken, 1) &&
(Token::Match(tok->previous(), "( 0 [|+]") ||
Token::Match(tok->previous(), "[|+-] 0 )"))) {
tok = tok->previous();
if (Token::Match(tok, "[|+-]"))
tok = tok->previous();
@ -2200,10 +2267,13 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
ret = true;
}
if (Token::Match(tok, "%num% %comp% %num%") &&
if (validTokenEnd(bounded, tok, backToken, 2) &&
Token::Match(tok, "%num% %comp% %num%") &&
MathLib::isInt(tok->str()) &&
MathLib::isInt(tok->strAt(2))) {
if (Token::Match(tok->previous(), "(|&&|%oror%") && Token::Match(tok->tokAt(3), ")|&&|%oror%|?")) {
if (validTokenStart(bounded, tok, frontToken, -1) &&
Token::Match(tok->previous(), "(|&&|%oror%") &&
Token::Match(tok->tokAt(3), ")|&&|%oror%|?")) {
const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
const std::string &cmp(tok->next()->str());
const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2)));

View File

@ -141,6 +141,7 @@ private:
TEST_CASE(template101); // #8968
TEST_CASE(template102); // #9005
TEST_CASE(template103);
TEST_CASE(template104); // #9021
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_enum); // #6299 Syntax error in complex enum declaration (including template)
@ -184,6 +185,8 @@ private:
TEST_CASE(templateTypeDeduction1); // #8962
TEST_CASE(templateTypeDeduction2);
TEST_CASE(simplifyTemplateArgs);
}
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
@ -1275,7 +1278,7 @@ private:
"void foo ( ) { "
"Foo<true> myFoo ; "
"} struct Foo<true> { "
"std :: array < int , true ? 1 : 2 > mfoo ; "
"std :: array < int , 1 > mfoo ; "
"} ;";
ASSERT_EQUALS(expected, tok(code, true));
ASSERT_EQUALS("", errout.str());
@ -2354,6 +2357,32 @@ private:
ASSERT_EQUALS(exp, tok(code));
}
void template104() { // #9021
const char code[] = "template < int i >\n"
"auto key ( ) { return hana :: test :: ct_eq < i > { } ; }\n"
"template < int i >\n"
"auto val ( ) { return hana :: test :: ct_eq < - i > { } ; }\n"
"template < int i , int j >\n"
"auto p ( ) { return :: minimal_product ( key < i > ( ) , val < j > ( ) ) ; }\n"
"int main ( ) {\n"
" BOOST_HANA_CONSTANT_CHECK ( hana :: equal (\n"
" hana :: at_key ( hana :: make_map ( p < 0 , 0 > ( ) ) , key < 0 > ( ) ) ,\n"
" val < 0 > ( ) ) ) ;\n"
"}";
const char exp[] = "auto key<0> ( ) ; "
"auto val<0> ( ) ; "
"auto p<0,0> ( ) ; "
"int main ( ) { "
"BOOST_HANA_CONSTANT_CHECK ( hana :: equal ( "
"hana :: at_key ( hana :: make_map ( p<0,0> ( ) ) , key<0> ( ) ) , "
"val<0> ( ) ) ) ; "
"} "
"auto p<0,0> ( ) { return :: minimal_product ( key<0> ( ) , val<0> ( ) ) ; } "
"auto val<0> ( ) { return hana :: test :: ct_eq < - 0 > { } ; } "
"auto key<0> ( ) { return hana :: test :: ct_eq < 0 > { } ; }";
ASSERT_EQUALS(exp, tok(code));
}
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
const char code[] = "template <typename T> struct C {};\n"
"template <typename T> struct S {a};\n"
@ -3435,6 +3464,23 @@ private:
TODO_ASSERT_EQUALS(expected, actual, tok(code));
}
void simplifyTemplateArgs() {
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 2 ) >;"));
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < 1 + 1 >;"));
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 1 + 1 ) >;"));
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < ( 2 ), ( 2 ) >;"));
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < 1 + 1, 1 + 1 >;"));
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < ( 1 + 1 ), ( 1 + 1 ) >;"));
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < true ? true : false >;"));
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < false ? true : false >;"));
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < 1 ? true : false >;"));
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < 0 ? true : false >;"));
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < (1 + 1 ) ? true : false >;"));
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < ( 1 - 1) ? true : false >;"));
}
};
REGISTER_TEST(TestSimplifyTemplate)