Fix #9225 (Crash on valid C++14 code) (#2031)

* Fix #9225 (Crash on valid C++14 code)

This only fixes the crash. Specialization of nested templates is still
broken.

* fix cppcheck warnings

* fixed another cppcheck warning
This commit is contained in:
IOBYTE 2019-07-24 13:20:19 -04:00 committed by Daniel Marjamäki
parent bbcffce529
commit 999d2f797c
4 changed files with 146 additions and 8 deletions

View File

@ -79,7 +79,21 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s,
// only set flags for declaration
if (token && nameToken && paramEnd) {
isSpecialization(Token::simpleMatch(token, "template < >"));
isPartialSpecialization(!isSpecialization() && nameToken->strAt(1) == "<");
if (!isSpecialization()) {
if (Token::simpleMatch(token->next()->findClosingBracket(), "> template <")) {
const Token * temp = nameToken->tokAt(-2);
while (Token::Match(temp, ">|%name% ::")) {
if (temp->str() == ">")
temp = temp->findOpeningBracket()->previous();
else
temp = temp->tokAt(-2);
}
isPartialSpecialization(temp->strAt(1) == "<");
} else
isPartialSpecialization(nameToken->strAt(1) == "<");
}
isAlias(paramEnd->strAt(1) == "using");
if (isAlias() && isPartialSpecialization()) {
@ -775,6 +789,19 @@ bool TemplateSimplifier::getTemplateDeclarations()
// ignore template template parameter
if (tok->strAt(-1) == "<")
continue;
// ignore nested template
if (tok->strAt(-1) == ">")
continue;
// skip to last nested template parameter
const Token *tok1 = tok;
while (tok1 && tok1->next() && Token::simpleMatch(tok1->next()->findClosingBracket(), "> template <")) {
const Token *closing = tok1->next()->findClosingBracket();
if (!closing)
syntaxError(tok1->next());
tok1 = closing->next();
}
if (!tok1)
syntaxError(tok);
// Some syntax checks, see #6865
if (!tok->tokAt(2))
syntaxError(tok->next());
@ -782,7 +809,7 @@ bool TemplateSimplifier::getTemplateDeclarations()
!Token::Match(tok->tokAt(3), "%name%|.|,|=|>"))
syntaxError(tok->next());
codeWithTemplates = true;
const Token * const parmEnd = tok->next()->findClosingBracket();
const Token * const parmEnd = tok1->next()->findClosingBracket();
for (const Token *tok2 = parmEnd; tok2; tok2 = tok2->next()) {
if (tok2->str() == "(" && tok2->link())
tok2 = tok2->link();
@ -1403,9 +1430,9 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateFunction(const Token *to
if (Token::Match(tok->next(), ";|{"))
return false;
// skip decltype(...)
else if (Token::simpleMatch(tok, "decltype (")) {
const Token * end = tok->linkAt(1);
while (tok && tok != end) {
else if (Token::simpleMatch(tok->next(), "decltype (")) {
const Token * end = tok->linkAt(2)->previous();
while (tok && tok->next() && tok != end) {
tok = tok->next();
namepos++;
}
@ -1863,6 +1890,7 @@ void TemplateSimplifier::expandTemplate(
if (tok5)
tok5 = tok5->next();
// copy return type
std::stack<Token *> brackets2; // holds "(" and "{" tokens
while (tok5 && tok5 != tok3) {
// replace name if found
if (Token::Match(tok5, "%name% <") && tok5->str() == templateInstantiation.name) {
@ -1924,8 +1952,28 @@ void TemplateSimplifier::expandTemplate(
}
}
}
if (!added)
if (!added) {
mTokenList.addtoken(tok5, tok5->linenr(), tok5->fileIndex());
Token *back = mTokenList.back();
if (Token::Match(back, "{|(|[")) {
brackets2.push(back);
} else if (back->str() == "}") {
assert(brackets2.empty() == false);
assert(brackets2.top()->str() == "{");
Token::createMutualLinks(brackets2.top(), back);
brackets2.pop();
} else if (back->str() == ")") {
assert(brackets2.empty() == false);
assert(brackets2.top()->str() == "(");
Token::createMutualLinks(brackets2.top(), back);
brackets2.pop();
} else if (back->str() == "]") {
assert(brackets2.empty() == false);
assert(brackets2.top()->str() == "[");
Token::createMutualLinks(brackets2.top(), back);
brackets2.pop();
}
}
}
tok5 = tok5->next();

View File

@ -111,7 +111,7 @@ const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &end
tok = tok->linkAt(1)->next();
if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
tok = tok->linkAt(1)->next();
if (tok && tok->str() == ".") { // trailing return type
if (tok && tok->originalName() == "->") { // trailing return type
for (tok = tok->next(); tok && !Token::Match(tok, ";|{|override|final"); tok = tok->next())
if (tok->link() && Token::Match(tok, "<|[|("))
tok = tok->link();

View File

@ -1592,7 +1592,6 @@ private:
void garbageCode203() { // #8972
checkCode("{ > () {} }");
checkCode("template <> a > ::b();");
ASSERT_THROW(checkCode("{ template <a> class b { } template <> template <c> c() b<a>::e() { } template b<d>; }"), InternalError);
}
void garbageCode204() {

View File

@ -164,6 +164,7 @@ private:
TEST_CASE(template124); // #9197
TEST_CASE(template125);
TEST_CASE(template126); // #9217
TEST_CASE(template127); // #9225
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)
@ -2943,6 +2944,96 @@ private:
ASSERT_EQUALS(exp, tok(code));
}
void template127() { // #9225
{
const char code[] = "template <typename> struct a {\n"
" template <typename b> constexpr decltype(auto) operator()(b &&) const;\n"
"};\n"
"a<int> c;\n"
"template <typename d>\n"
"template <typename b>\n"
"constexpr decltype(auto) a<d>::operator()(b &&) const {}";
const char exp[] = "struct a<int> ; "
"a<int> c ; "
"template < typename d > "
"template < typename b > "
"const decltype ( auto ) a < d > :: operator() ( b & & ) const { } "
"struct a<int> { "
"template < typename b > const decltype ( auto ) operator() ( b & & ) const ; "
"} ;";
const char act[] = "struct a<int> ; "
"a<int> c ; "
"template < typename d > "
"template < typename b > "
"const decltype ( auto ) a < d > :: operator() ( b & & ) const { } "
"struct a<int> { "
"template < typename b > const decltype ( auto ) operator() ( b & & ) const ; "
"} ; "
"const decltype ( auto ) a<int> :: operator() ( b & & ) const { }";
TODO_ASSERT_EQUALS(exp, act, tok(code));
}
{
const char code[] = "template <typename> struct a {\n"
" template <typename b> static void foo();\n"
"};\n"
"a<int> c;\n"
"template <typename d>\n"
"template <typename b>\n"
"void a<d>::foo() {}\n"
"void bar() { a<int>::foo<char>(); }";
const char exp[] = "struct a<int> ; "
"a<int> c ; "
"template < typename d > "
"template < typename b > "
"void a < d > :: foo ( ) { } "
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
"struct a<int> { "
"template < typename b > static void foo ( ) ; "
"static void foo<char> ( ) ; "
"} ; "
"void a<int> :: foo<char> ( ) { }";
const char act[] = "struct a<int> ; "
"a<int> c ; "
"template < typename d > "
"template < typename b > "
"void a < d > :: foo ( ) { } "
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
"struct a<int> { "
"template < typename b > static void foo ( ) ; "
"} ; "
"void a<int> :: foo ( ) { }";
TODO_ASSERT_EQUALS(exp, act, tok(code));
}
{
const char code[] = "template <typename> struct a {\n"
" template <typename b> static void foo();\n"
"};\n"
"template <typename d>\n"
"template <typename b>\n"
"void a<d>::foo() {}\n"
"void bar() { a<int>::foo<char>(); }";
const char exp[] = "struct a<int> ; "
"template < typename d > "
"template < typename b > "
"void a < d > :: foo ( ) { } "
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
"struct a<int> { "
"static void foo<char> ( ) ; "
"} ; "
"void a<int> :: foo<char> ( ) { }";
const char act[] = "struct a<int> ; "
"template < typename d > "
"template < typename b > "
"void a < d > :: foo ( ) { } "
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
"struct a<int> { "
"template < typename b > static void foo ( ) ; "
"} ; "
"void a<int> :: foo ( ) { }";
TODO_ASSERT_EQUALS(exp, act, 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"